selecting entire hierarchy of rows from a self referencing table [duplicate] - sql-server

This question already has answers here:
Get hierarchical structure using SQL Server
(4 answers)
Closed 4 years ago.
I have a table that contains a self referencing foreign key. Sort of like an employees table where each employee has reporting manager and it is hierarchical. Here is an image of such a table. In this table, the ParentId is a foreign key pointing to the Id column.
So, the question is I want to run a select query on this table with a given Id which should return all the parents that are hierarchically connected to the asking Id. In other words, for example, if I ask for Id 14, it should return me Ids
[14 - 11 - q],
[11 - 8 - m],
[8 - 7 - j],
[7 - 4 - h],
[4 - 2 - e],
[2 - 1 - c],
[1 - 1 - b].
Can somebody show me what the query should be in T-SQL? Thanks.

Yes you can do this via a recursive CTE like below
See live demo
; with rcte as
(
select id, parentid, name
from yourtable
where id=8
union all
select t.id,t.parentid,t.name
from yourtable t join rcte r
on t.id=r.parentid and t.id<>t.parentid
)
select * from rcte option (maxrecursion 0);

Related

Return Only Top Row of SQL Server from duplicated data but different id [duplicate]

This question already has answers here:
Get top 1 row of each group
(19 answers)
Closed 5 months ago.
I have the below table:
ID|NAME|CREATED |TYPE|CARD_NO|
======================================
1 |JOHN|2022-09-21 09:00| 1 |1111111|
2 |JOHN|2022-09-21 09:05| 2 |1111111|
3 |DOE |2022-09-21 09:00| 1 |2222222|
4 |DOE |2022-09-21 09:05| 2 |2222222|
5 |DOE |2022-09-21 09:10| 3 |2222222|
I want to return only the most recent datatime of each row like below:
ID|NAME|CREATED |TYPE|CARD_NO|
======================================
2 |JOHN|2022-09-21 09:05| 2 |1111111|
5 |DOE |2022-09-21 09:10| 3 |2222222|
My query is:
SELECT ID, NAME,MAX(CREATED),TYPE,CARD_NO FROM users group by ID,NAME,TYPE,CARD_NO
However the result is not what I expected, please help me. thank you.
Use ROW_NUMBER coupled with a common table expression or derived table to work out the latest row
;with GetLatestRow
AS(
SELECT RN=row_number()over(partition by t.[name] order by t.Created DESC), --desc to put the lastest row on top
t.*
FROM users t
)
SELECT ID, NAME, CREATED,TYPE,CARD_NO
FROM GetLatestRow
WHERE RN=1

Improve a query with Pivot and Recursive code in SQL Server

I need to reach the next result considering these two tables.
An area receives services from different departments. Each department belongs to a hierarchy on three (or fewer) levels. The idea is to represent in one column the relationship between the area and all the hierarchies where it can be present. The Level Nro should be 1 for the record that does not have any father.
So far, I have this code https://rextester.com/KYHKR17801 . I've got the result that I need. However, the performance is not the best because the table is too large, and I had to do many transformations:
Pivot
Recursion
Addition of register because I lost the nulls when creating the Pivot table
Update the level Nro
I do not if anyone can give any advice to improve the runtime of this query.
This appears to do everything you need in one statement:
WITH R AS
(
SELECT
SA.AreaID,
S.[service],
S.[description],
L.[Level],
L.child_service,
Recursion = 1
FROM dbo.service_area AS SA
JOIN dbo.[service] AS S
ON S.[service] = SA.[Service]
OUTER APPLY
(
-- Unpivot
VALUES
(1, S.level1),
(2, S.level2),
(3, S.level3)
) AS L ([Level], child_service)
WHERE
L.child_service IS NOT NULL
UNION ALL
SELECT
R.AreaID,
S.[service],
S.[description],
R.[Level],
child_service = CHOOSE(R.[Level], S.level1, S.level2, S.level3),
Recursion = R.Recursion + 1
FROM R
JOIN dbo.[service] AS S
ON S.[service] = R.child_service
)
SELECT
R.AreaID,
R.[service],
R.[description],
[Level] = 'Level' + CONVERT(char(1), R.[Level]),
[Level Nro] = ROW_NUMBER() OVER (
PARTITION BY R.AreaID, R.[Level]
ORDER BY R.Recursion DESC)
FROM R
ORDER BY
R.AreaID ASC,
R.[Level] ASC,
[Level Nro]
OPTION (MAXRECURSION 3);
The following index will help the recursive section locate rows quickly:
CREATE UNIQUE CLUSTERED INDEX cuq ON dbo.[service] ([service]);
db<>fiddle demo
If your version of SQL Server doesn't have CHOOSE, write the CASE statement out by hand:
CASE R.[Level] WHEN 1 THEN S.level1 WHEN 2 THEN S.level2 ELSE S.level3 END

bring column name into row in sql server [duplicate]

This question already has answers here:
Unpivot with column name
(3 answers)
Closed 4 years ago.
I have a table with column column_name_1 , column_name_2 , column_name_3 and with one row values 0,0,1
column_name_1 , column_name_2 , column_name_3
--------------,----------------,---------------
0 , 0 , 1
I need output like
column_name_1 | 0
column_name_2 | 0
column_name_3 | 1
Is it possible?
I have checked for some unpivot example, thats not exactly my case.
Because I need Column name into column value and one row into column.
1.Unpivot with column name
Name, Maths, Science, English
Tilak, 90, 40, 60
Raj, 30, 20, 10
changed into
Name, Subject, Marks
Tilak, Maths, 90
Tilak, Science, 40
Tilak, English, 60
Clearly there is a view, Name column remains its position as it is.
2.SQL Query for generating matrix like output querying related table in SQL Server
Above link also have Customer Name column which is remains same as it is.
But in my case input and output, both not have any same position.
So if still it can be achievable through pivot, Pls help with the code.
Clearly UNPIVOT would be more performant, but if you need a dynamic approach without actually using dynamic SQL
Example
Select C.*
From YourTable A
Cross Apply ( values (cast((Select A.* for XML RAW) as xml))) B(XMLData)
Cross Apply (
Select Item = a.value('local-name(.)','varchar(100)')
,Value = a.value('.','varchar(max)')
From B.XMLData.nodes('/row') as C1(n)
Cross Apply C1.n.nodes('./#*') as C2(a)
Where a.value('local-name(.)','varchar(100)') not in ('Columns','ToExclude')
) C
Returns
Item Value
Column_name_1 0
column_name_2 0
column_name_3 1
You want APPLY :
SELECT tt.cols, tt.colsvalue
FROM table t CROSS APPLY
( VALUES ([column_name_1], 'column_name_1'),
([column_name_2], 'column_name_2'),
([column_name_3], 'column_name_3')
) tt (colsvalue, cols);

SQL Server Temp Table of Sequential Integers As Lookup [duplicate]

This question already has answers here:
Create Temp Table with Range of Numbers
(2 answers)
Closed 6 years ago.
I am trying to create a temporary table that has sequential integer values from 1 to 1,000 for use as a LEFT JOIN on my table that has the following sub-set of records:
USRNO EVSTRING
1 John Doe
10 Jane Doe
13 Jason Doe
16 Jeremy Doe
I'm attempting to identify the user numbers (USRNO) that do NOT appear in the records returned above (ie: find the missing user numbers).
I'd like to do this with a single SQL statement if possible, and would like to create the temp table "on the fly" (not create the table in advance).
How can I create a temporary table that is populated with an integer field with values from 1 to 1,000 sequentially?
Using SQL Server 2012.
The canonical way uses a recursive CTE:
with n as (
select 1 as n
union all
select n + 1
from n
where n < 1000
)
select n.n
from n
where not exists (select 1 from t where t.userno = n.n)
option (MAXRECURSION 0);

SQL Join one-to-many tables, selecting only most recent entries

This is my first post - so I apologise if it's in the wrong seciton!
I'm joining two tables with a one-to-many relationship using their respective ID numbers: but I only want to return the most recent record for the joined table and I'm not entirely sure where to even start!
My original code for returning everything is shown below:
SELECT table_DATES.[date-ID], *
FROM table_CORE LEFT JOIN table_DATES ON [table_CORE].[core-ID] = table_DATES.[date-ID]
WHERE table_CORE.[core-ID] Like '*'
ORDER BY [table_CORE].[core-ID], [table_DATES].[iteration];
This returns a group of records: showing every matching ID between table_CORE and table_DATES:
table_CORE date-ID iteration
1 1 1
1 1 2
1 1 3
2 2 1
2 2 2
3 3 1
4 4 1
But I need to return only the date with the maximum value in the "iteration" field as shown below
table_CORE date-ID iteration Additional data
1 1 3 MoreInfo
2 2 2 MoreInfo
3 3 1 MoreInfo
4 4 1 MoreInfo
I really don't even know where to start - obviously it's going to be a JOIN query of some sort - but I'm not sure how to get the subquery to return only the highest iteration for each item in table 2's ID field?
Hope that makes sense - I'll reword if it comes to it!
--edit--
I'm wondering how to integrate that when I'm needing all the fields from table 1 (table_CORE in this case) and all the fields from table2 (table_DATES) joined as well?
Both tables have additional fields that will need to be merged.
I'm pretty sure I can just add the fields into the "SELECT" and "GROUP BY" clauses, but there are around 40 fields altogether (and typing all of them will be tedious!)
Try using the MAX aggregate function like this with a GROUP BY clause.
SELECT
[ID1],
[ID2],
MAX([iteration])
FROM
table_CORE
LEFT JOIN table_DATES
ON [table_CORE].[core-ID] = table_DATES.[date-ID]
WHERE
table_CORE.[core-ID] Like '*' --LIKE '%something%' ??
GROUP BY
[ID1],
[ID2]
Your example field names don't match your sample query so I'm guessing a little bit.
Just to make sure that I have everything you’re asking for right, I am going to restate some of your question and then answer it.
Your source tables look like this:
table_core:
table_dates:
And your outputs are like this:
Current:
Desired:
In order to make that happen all you need to do is use a subquery (or a CTE) as a “cross-reference” table. (I used temp tables to recreate your data example and _ in place of the - in your column names).
--Loading the example data
create table #table_core
(
core_id int not null
)
create table #table_dates
(
date_id int not null
, iteration int not null
, additional_data varchar(25) null
)
insert into #table_core values (1), (2), (3), (4)
insert into #table_dates values (1,1, 'More Info 1'),(1,2, 'More Info 2'),(1,3, 'More Info 3'),(2,1, 'More Info 4'),(2,2, 'More Info 5'),(3,1, 'More Info 6'),(4,1, 'More Info 7')
--select query needed for desired output (using a CTE)
; with iter_max as
(
select td.date_id
, max(td.iteration) as iteration_max
from #table_dates as td
group by td.date_id
)
select tc.*
, td.*
from #table_core as tc
left join iter_max as im on tc.core_id = im.date_id
inner join #table_dates as td on im.date_id = td.date_id
and im.iteration_max = td.iteration
select *
from
(
SELECT table_DATES.[date-ID], *
, row_number() over (partition by table_CORE date-ID order by iteration desc) as rn
FROM table_CORE
LEFT JOIN table_DATES
ON [table_CORE].[core-ID] = table_DATES.[date-ID]
WHERE table_CORE.[core-ID] Like '*'
) tt
where tt.rn = 1
ORDER BY [core-ID]

Resources