I have a below table
ID Level StoreId
2678540 3 A
2678540 7 A
2678540 3 B
2678540 7 B
2678540 3 C
I need out put like Below
ID A B C D E
2678540 3 3 3 0 0
2678540 3 7 3 0 0
2678540 7 3 3 0 0
2678540 7 7 3 0 0
Please help me how to achieve this.
If StoreID 'A' always exists:
select tA.ID, tA.Level as A, tB.Level as B, tC.Level as C , 0 as D, 0 as E
from Table1 tA
cross apply (select Level from Table1 t2 where tA.Id=t2.Id and t2.StoreId = 'B') tB
cross apply (select Level from Table1 t2 where tA.Id=t2.Id and t2.StoreId = 'C') tC
where tA.StoreId = 'A'
Related
I have following table with hierarchical data:
FolderId ParentFolderId NumberOfAffectedItems
---------------------------------------------
1 NULL 2
2 1 3
3 2 5
4 2 3
5 1 0
I want to find number of affected items under each folders and all of its children. I can write a recursive cte, which can produce following result, after that by doing group by I can find out what I want.
Normal recursive CTE:
WITH FolderTree AS
(
SELECT
fsa.FolderId AS ParentFolderId,
fsa.FolderId AS ChildFolderId,
fsa.NumberOfReportsAffected
FROM
FoldersWithNumberOfReportsAffected fsa
UNION ALL
SELECT
ft.ParentFolderId,
fsa.FolderId AS ChildFolderId,
fsa.NumberOfReportsAffected
FROM
FoldersWithNumberOfReportsAffected fsa
INNER JOIN
FolderTree ft ON fsa.ParentFolderId = ft.ChildFolderId
)
Result:
ParentFolderId ChildFolderId NumberOfAffectedItems
--------------------------------------------------
1 1 2
1 2 3
1 3 5
1 4 3
1 5 0
2 2 3
2 3 5
2 4 3
3 3 5
4 4 3
5 5 0
But I want to optimize it, I want to start from the leaf child, while
moving through the CTE itself, I want to compute NumberOfAffectedItems.
Expected CTE
WITH FolderTree AS
(
SELECT
fsa.FolderId AS LeafChildId,
fsa.FolderId AS ParentFolderId,
fsa.NumberOfReportsAffected
FROM
FoldersWithNumberOfReportsAffected fsa
LEFT JOIN
FoldersWithNumberOfReportsAffected f ON fsa.folderid = f.ParentfolderId
WHERE
f.ParentfolderId is null -- this is finding leaf child
UNION ALL
SELECT
ft.LeafChildId,
fsa.FolderId AS ParentFolderId,
fsa.NumberOfReportsAffected + ft.NumberOfReportsAffected AS [ComputedResult]
FROM
FoldersWithNumberOfReportsAffected fsa
INNER JOIN
FolderTree ft ON fsa.FolderId = ft.ParentFolderId
)
Result:
LeafChildId ParentFolderId ComputedNumberOfAffectedItems
---------------------------------------------------------
3 3 5
3 2 8
3 1 10
4 4 3
4 2 5
4 1 7
5 5 0
5 1 2
If I group by ParentFolderId, I will get a wrong result, the reason is while doing computing in CTE, the same parent folder is visited from multiple
children, hence results in a wrong result. I want to find out is there anyway we can compute the result while going through the CTE itself.
Please check the following solution. I used your cte as basis and added the calculation (as column x) to it:
DECLARE #t TABLE(
FolderID INT
,ParentFolderID INT
,NumberOfAffectedItems INT
);
INSERT INTO #t VALUES (1 ,NULL ,2)
,(2 ,1 ,3)
,(3 ,2 ,5)
,(4 ,2 ,3)
,(5 ,1 ,0);
WITH FolderTree AS
(
SELECT 1lvl,
fsa.FolderId AS LeafChildId,
fsa.ParentFolderId AS ParentFolderId,
fsa.NumberOfAffectedItems
FROM
#t fsa
LEFT JOIN
#t f ON fsa.folderid = f.ParentfolderId
WHERE
f.ParentfolderId is null -- this is finding leaf child
UNION ALL
SELECT lvl + 1,
ft.LeafChildId,
fsa.ParentFolderId,
fsa.NumberOfAffectedItems
FROM
FolderTree ft
INNER JOIN #t fsa
ON fsa.FolderId = ft.ParentFolderId
)
SELECT LeafChildId,
ISNULL(ParentFolderId, LeafChildId) ParentFolderId,
NumberOfAffectedItems,
SUM(NumberOfAffectedItems) OVER (PARTITION BY LeafChildId ORDER BY ISNULL(ParentFolderId, LeafChildId) DESC) AS x
FROM FolderTree
ORDER BY 1, 2 DESC
OPTION (MAXRECURSION 0)
Result:
LeafChildId ParentFolderId NumberOfAffectedItems x
3 3 2 2
3 2 5 7
3 1 3 10
4 4 2 2
4 2 3 5
4 1 3 8
5 5 2 2
5 1 0 2
We have a table with a parent child relationship, that represents a deep tree structure.
We are using a view with a CTE to query the data but the performance is poor (see code and execution plan below).
Is there any way we can improve the performance?
WITH cte (ParentJobTypeId, Id) AS
(
SELECT
Id, Id
FROM
dbo.JobTypes
UNION ALL
SELECT
e.Id, cte.Id
FROM
cte
INNER JOIN
dbo.JobTypes AS e ON e.ParentJobTypeId = cte.ParentJobTypeId
)
SELECT
ISNULL(Id, 0) AS ParentJobTypeId,
ISNULL(ParentJobTypeId, 0) AS Id
FROM
cte
A quick example of using the range keys. As I mentioned before, hierarchies were 127K points and some sections where 15 levels deep
The cte Builds, let's assume the hier results will be will be stored in a table (indexed as well)
Declare #Table table(ID int,ParentID int,[Status] varchar(50))
Insert #Table values
(1,101,'Pending'),
(2,101,'Complete'),
(3,101,'Complete'),
(4,102,'Complete'),
(101,null,null),
(102,null,null)
;With cteOH (ID,ParentID,Lvl,Seq)
as (
Select ID,ParentID,Lvl=1,cast(Format(ID,'000000') + '/' as varchar(500)) from #Table where ParentID is null
Union All
Select h.ID,h.ParentID,cteOH.Lvl+1,Seq=cast(cteOH.Seq + Format(h.ID,'000000') + '/' as varchar(500)) From #Table h INNER JOIN cteOH ON h.ParentID = cteOH.ID
),
cteR1 as (Select ID,Seq,R1=Row_Number() over (Order by Seq) From cteOH),
cteR2 as (Select A.ID,R2 = max(B.R1) From cteOH A Join cteR1 B on (B.Seq Like A.Seq+'%') Group By A.ID)
Select B.R1
,C.R2
,A.Lvl
,A.ID
,A.ParentID
Into #TempHier
From cteOH A
Join cteR1 B on (A.ID=B.ID)
Join cteR2 C on (A.ID=C.ID)
Select * from #TempHier
Select H.R1
,H.R2
,H.Lvl
,H.ID
,H.ParentID
,Total = count(*)
,Complete = sum(case when D.Status = 'Complete' then 1 else 0 end)
,Pending = sum(case when D.Status = 'Pending' then 1 else 0 end)
,PctCmpl = format(sum(case when D.Status = 'Complete' then 1.0 else 0.0 end)/count(*),'##0.00%')
From #TempHier H
Join (Select _R1=B.R1,A.* From #Table A Join #TempHier B on A.ID=B.ID) D on D._R1 between H.R1 and H.R2
Group By H.R1
,H.R2
,H.Lvl
,H.ID
,H.ParentID
Order By 1
Returns the hier in a #Temp table for now. Notice the R1 and R2, I call these the range keys. Data (without recursion) can be selected and aggregated via these keys
R1 R2 Lvl ID ParentID
1 4 1 101 NULL
2 2 2 1 101
3 3 2 2 101
4 4 2 3 101
5 6 1 102 NULL
6 6 2 4 102
VERY SIMPLE EXAMPLE: Illustrates the rolling the data up the hier.
R1 R2 Lvl ID ParentID Total Complete Pending PctCmpl
1 4 1 101 NULL 4 2 1 50.00%
2 2 2 1 101 1 0 1 0.00%
3 3 2 2 101 1 1 0 100.00%
4 4 2 3 101 1 1 0 100.00%
5 6 1 102 NULL 2 1 0 50.00%
6 6 2 4 102 1 1 0 100.00%
The real beauty of the the range keys, is if you know an ID, you know where it exists (all descendants and ancestors).
I'm naive to SQL...pls help me with my below query:
I have a table named Course as shown below:
Key CourseName CourseId IsCurrentVersion
0 Course_1 A 0
1 Course_1 A 0
2 Course_1 A 1
3 Course_2 B 0
4 Course_2 B 0
5 Course_3 C 1
6 Course_4 D 0
7 Course_5 E 0
8 Course_5 E 0
9 Course_6 F 1
10 Course_6 F 1
11 Course_6 F 1
12 Course_7 G 1
13 Course_7 G 0
14 Course_7 G 0
I want the below result set:
CourseName CourseId IsCurrentVersion
Course_1 A 1
Course_2 B 0
Course_3 C 1
Course_4 D 0
Course_5 E 0
Course_6 F 1
Course_7 G 1
For records having same CourseId; IsCurrentVersion having 1 should be preferred to 0. Single records should also get displayed in output irrespective of their IsCurrentVersion values.
Database is SQL Server 2008.
Try this:
SELECT CourseName, CourseId, IsCurrentVersion
FROM Course AS A
WHERE IsCurrentVersion = (SELECT MAX(IsCurrentVersion)
FROM Course AS B
WHERE A.CourseId = B.CourseId)
GROUP BY CourseName, CourseID, IsCurrentVersion
This should get you what you are looking for, assuming the only values for IsCurrentVersion are 1 and 0.
SELECT CourseName, CourseId, MAX(IsCurrentVersion)
FROM Course
GROUP BY CourseName, CourseID
If the IsCurrentVersion column is a bit and not an integer, use this instead.
SELECT CourseName, CourseId, MAX(CASE WHEN IsCurrentVersion = 1 THEN 1 ELSE 0 END)
FROM Course
GROUP BY CourseName, CourseID
Let's say I have this table MyTbl
Record Id_try Id Type IsOk DateOk
1 1 MYDB00125 A 0 NULL
2 1 MYDB00125 B 1 2012-07-19 20:10:05.000
3 1 MYDB00125 A 0 2012-07-25 14:10:05.000
4 2 MYDB00125 A 0 2012-07-19 22:10:05.000
5 1 MYDB00254 B 0 2012-07-19 22:10:05.000
6 1 MYDB00254 A 0 NULL
7 3 MYDB00125 A 1 2012-07-19 22:15:05.000
8 3 MYDB00125 B 1 2012-07-19 22:42:53.000
9 1 MYDB00323 A 1 2012-07-22 00:15:05.00 0
10 1 MYDB00323 C 0 NULL
And I want a group by that brings me for each Id and Type my last "Id_Try Record".
SELECT Id, MAX(Id_Try), MyTbl.Type, IsOK, MAX(DateOk) from MyTbl
GROUP BY Id, MyTbl.Type, IsOK
Won't do, because It'll bring me the last Id_Try AND the last date (Date of record 3 in the example). And I don't care if its the last date or not, I need the date of the last Id_Try.
Is this only solved by a subselect? or a having clause could do?
This is the result expected:
Record Id_try Id Type IsOk DateOk
5 1 MYDB00254 B 0 2012-07-19 22:10:05.000
6 1 MYDB00254 A 0 NULL
7 3 MYDB00125 A 1 2012-07-19 22:15:05.000
8 3 MYDB00125 B 1 2012-07-19 22:42:53.000
9 1 MYDB00323 A 1 2012-07-22 00:15:05.00 0
10 1 MYDB00323 B 0 NULL
I think you will need to break this into two pieces:
with maxIDTry as
(
SELECT MAX(Id_try) as maxId, ID
FROM MyTable
GROUP BY ID
)
SELECT * FROM MyTable as mt
INNER JOIN maxIDTry as max
ON mt.id_try = max.maxId AND mt.id = max.id
I think you want this:
select * FROM
(
select *, row_number() over (partition by id,type order by Id_try desc) as position from mytbl
) foo
where position = 1
order by record
http://www.sqlfiddle.com/#!3/95742/5
Your sample result set lists
9 1 MYDB00323 A 1 2012-07-22 00:15:05.00 0
10 1 MYDB00323 A 0 NULL
But that doesn't make sense since you're saying the ID and the Id_try have the same value. I assume you meant for Id_try to be 2 maybe? Otherwise I think my results match up.
Hope this helps.
SELECT A.Record, A.Id_try, A.Id, A.Type, A.IsOk, A.DateOk
FROM MyTbl A INNER JOIN (
SELECT MAX(Id_Try) Id_Try, Id, B1.Type
from MyTbl B1
GROUP BY Id, B1.Type) AS B
ON A.Id_Try = B.Id_Try AND A.Id = B.Id AND A.Type = B.Type
ORDER BY A.RECORD
Refresh my memory. I can't recall how to join tuples (a,b) and (c) to produce (a,b)*(c). For example:
n
---
0
1
2
And
site_id value
----------- -------------
1 a
1 b
2 c
I'd like to end up with:
site_id value n
----------- -------------- --
1 a 0
1 a 1
1 a 2
1 b 0
1 b 1
1 b 2
2 c 0
2 c 1
2 c 2
How can I achieve this?
That's called a CROSS JOIN, also known as the Cartesian product.
SELECT *
FROM Table1
CROSS JOIN Table2
You can also do it without the JOIN keyword just by using a comma:
SELECT * FROM Table1, Table2
Here's full test code you can use to verify that it works:
CREATE TABLE Table1 (n int NOT NULL);
INSERT INTO Table1 (n) VALUES
(0),
(1),
(2);
CREATE TABLE Table2 (site_id int NOT NULL, value nvarchar(100) NOT NULL);
INSERT INTO Table2 (site_id, value) VALUES
(1, 'a'),
(1, 'b'),
(2, 'c');
SELECT Table2.site_id, Table2.value, Table1.n FROM Table1, Table2
Results:
site_id value n
1 a 0
1 a 1
1 a 2
1 b 0
1 b 1
1 b 2
2 c 0
2 c 1
2 c 2
Do a CROSS JOIN
You can try
Select *
FROM table1, table2