SQL Server CTE query not getting desired result - sql

I have table with few columns & I am using a CTE to get data in a hierarchical order in sorted manner:
Cat 1
--item X1
--item X2
Cat 2
Cat 3
Cat 4
cat 5
--item A1
--item A2
Cat 6
Table data:
ID LanguageID Name ParentID Active
----------------------------------------------
1 1 Cat 1 0 1
2 1 item X1 1 1
3 1 item X2 1 1
4 1 cat 2 0 1
5 1 cat 3 0 0
6 1 cat 4 0 1
7 1 cat 5 0 1
8 1 item A1 7 1
9 1 item A2 7 0
10 1 cat 6 0 1
CTE query:
WITH CTE (ID, ParentID, Name, LanguageID, Active, Depth, SortCol) AS
(
SELECT
ID, ParentID, Name, LanguageID, Active, 0,
CAST(ID AS varbinary(max))
FROM
Project
WHERE
ParentID = 0 AND Active = 1
UNION ALL
SELECT
d.ID, d.ParentID, d.Name, p.LanguageID, p.Active, p.Depth + 1,
CAST(SortCol + CAST(d.ID AS binary(4)) AS varbinary(max))
FROM
Project AS d
JOIN
CTE AS p ON d.ParentID = p.ID
WHERE
p.Active = 1
)
SELECT
ID, ParentID, Name, LanguageID, Active, Depth,
REPLICATE(' ', Depth) + Name as HName
FROM
CTE
WHERE
LanguageID = 1 AND Active = 1
ORDER BY
Name
Above query hides the parent category but not the child items.
Second I am only able to order parent category in name but not the child items.
Expected output should be:
Cat 1
--item X1
--item X2
Cat 2
Cat 4
cat 5
--item A1
Cat 6
UPDATE: Just to mention I am not showing the all the columns of CTE query in above output below is the complete output of query
ID ParentID Name LanguageID Active Depth HName
------------------------------------------------------------------
1 0 Cat 1 1 1 0 Cat 1
4 1 item X1 1 1 0 item X1
7 1 item X2 1 1 0 item X2
8 0 cat 2 1 1 1 cat 2
9 0 cat 4 1 1 1 cat 4
10 0 cat 5 1 1 0 cat 5
3 7 item A1 1 1 1 item A1
2 7 item A2 1 1 1 item A2
6 0 cat 6 1 1 0 cat 6

you can use self join here. see the below query
select p.Name, c.Name,c.Active,c.Id,c.LanguageID
From Project c left outer join Project p
where c.ParentId = p.Id

Related

SQL Take Max and Include Non-Group By COLS

TABLE1
ID STUDENT SCORE TIME
A 1 9 1
A 1 8 2
B 1 0 1
B 1 10 2
B 1 7 3
C 2 5 1
C 2 1 2
C 2 0 3
D 3 1 1
E 3 0 1
D 3 4 2
D 3 4 3
E 3 9 2
F 4 6 1
G 4 6 1
WANT
ID STUDENT MAXSCORE TIME
A 1 9 1
B 1 10 2
B 1 7 3
C 2 5 1
C 2 1 2
C 2 0 3
D 3 1 1
E 3 9 2
D 3 4 3
F 4 6 1
I have TABLE1 and wish for WANT which does this:
for every STUDENT/TIME, select the row with the MAX(SCORE)
I try this::
select ID, STUDENT, MAX(SCORE) AS MAXSCORE, TIME
from TABLE1
group by STUDENT, TIME
But amn't able to include ID
First get the max score by student/time, then join back to the original table.
WITH dat
AS
(
SELECT student, time, MAX(score) AS max_score
FROM TABLE1
GROUP BY student, time
)
SELECT DISTINCT t.id, t.student, d.max_score, t.time
FROM TABLE1 t
INNER JOIN dat d
ON t.student = d.student AND t.time = d.time AND t.score = d.max_score;
If the RDBMS supports window functions, then
with cte as (
select id,
student,
score,
time,
row_number() over (partition by student, time order by score desc) as rn
from table1)
select id, student, score, time
from cte
where rn = 1;

SQL - Query to identify the parentid in a hierarchy with some conditions

I have a table in SQL azure database with a hierarchy of parents and i want to identify in the total hierarchy of the parents the parent id for each item that meets some conditions.
As an example this could be a great example
categoryId parentId Typeid
1 null 1
2 1 2
3 2 3
4 3 4
5 3 4
6 null 5
7 6 1
8 7 2
9 8 3
10 9 4
11 9 4
And I want to find for each categoryID the ParentId in the hierarchy that the type is 1 and if this category is the type 1 put the same category, in order to receive something like this.
categoryId parentId Typeid ParentSearch
1 null 1 1
2 1 2 1
3 2 3 1
4 3 4 1
5 3 4 1
6 null 5 null
7 6 1 7
8 7 2 7
9 8 3 7
10 9 4 7
11 9 4 7
As you can see all the categories from 1 to 5 the parent with type 1 is the category 1
and for the categories from 6 to 11, the 6 need to be null and the rest the parent is 7.
It could be possible?
Maybe creating a path or something. i have done doing several left joins at leves and it is fine but i dont want to create 500leves in order to be sure that we never have 500 levels childs.
Thanks and regards!
A recursive CTE is your friend:
WITH parents AS
(SELECT categoryid, parentid, typeid
, CASE WHEN typeid = 1 THEN categoryid ELSE NULL END AS parentsearch
FROM mytable
WHERE parentid IS NULL
UNION ALL
SELECT c.categoryid, c.parentid, c.typeid
, coalesce(p.parentsearch, CASE WHEN c.typeid = 1 THEN c.categoryid ELSE null END)
FROM mytable AS c
JOIN parents AS p ON c.parentid = p.categoryid)
SELECT * FROM parents ORDER BY categoryid;
categoryid parentid typeid parentsearch
---------- ---------- ---------- ------------
1 (null) 1 1
2 1 2 1
3 2 3 1
4 3 4 1
5 3 4 1
6 (null) 5 (null)
7 6 1 7
8 7 2 7
9 8 3 7
10 9 4 7
11 9 4 7
Sql Server db<>fiddle example.
Another solution that uses a recursive CTE.
But this one seeds from the childs.
WITH RCTE AS
(
SELECT t.categoryId, t.parentId, t.typeId,
0 as lvl,
t.categoryId as nextCategoryId,
t.parentId as nextParentId,
t.typeId as nextTypeId
FROM CategoryRelations t
UNION ALL
SELECT c.categoryId, c.parentId, c.typeId,
c.lvl + 1,
t.categoryId,
t.parentId,
t.typeId
FROM RCTE c
JOIN CategoryRelations t ON t.categoryId = c.nextParentId
WHERE c.typeId != 1
)
SELECT
c.categoryId,
c.parentId,
c.typeId,
(case when c.nextTypeId = 1 then c.nextCategoryId end) as ParentSearch
FROM RCTE c
WHERE (c.nextTypeId = 1 or c.parentId is null)
ORDER BY categoryId;
A test on rextester here

SQL recursive hierarchy

I am struggling to get one recursive CTE to work as desired but still with no chance..
So, I have the following similar table structures:
tblMapping:
map_id | type_id | name | parent_id
1 1 A1 0
2 1 A2 0
3 1 A3 1
4 1 A4 3
5 2 B1 0
6 2 B2 5
7 2 B3 6
8 1 A5 4
9 2 B4 0
tblRoleGroup:
role_group_id | type_id | map_id | desc_id
1 1 0 null
1 2 0 null
2 1 3 1
2 2 6 0
3 1 8 1
3 2 9 1
In tblRoleGroup, the desc_id field means:
null - allow all (used only in combination with map_id=0)
0 - allow all from parent including parent
1 - allow only current node
Still in tblRoleGroup if map_id=0 then the query should get all elements from same type_id
The query result should look like this:
role_group_id | type_id | map_id | path
1 1 1 A1
1 1 2 A2
1 1 3 A1.A3
1 1 4 A1.A3.A4
1 1 8 A1.A3.A4.A5
1 2 5 B1
1 2 6 B1.B2
1 2 7 B1.B2.B3
1 2 9 B4
2 1 3 A1.A3
2 2 6 B1.B2
2 2 7 B1.B2.B3
3 1 8 A1.A3.A4.A5
3 2 9 B4
The query below solves only a part of the expected result, but I wasn't able to make it work as the expected result..
WITH Hierarchy(map_id, type_id, name, Path) AS
(
SELECT t.map_id, t.type_id, t.name, CAST(t.name AS varchar(MAX)) AS Expr1
FROM dbo.tblMapping AS t
LEFT JOIN dbo.tblMapping AS t1 ON t1.map_id = t.parent_id
WHERE (t1.parent_id=0)
UNION ALL
SELECT t.map_id, t.type_id, t.name, CAST(h.Path + '.' + t.name AS varchar(MAX)) AS Expr1
FROM Hierarchy AS h
JOIN dbo.tblMapping AS t ON t.parent_id = h.map_id
)
SELECT h.map_id, h.type_id, t.role_group_id, h.Path AS Path
FROM Hierarchy AS h
LEFT JOIN dbo.tblRoleGroup t ON t.map_id = h.map_id
Could someone help me on this?
Thank you
At first I create a function that brings all descendants of passed map_id:
CREATE FUNCTION mapping (#map_id int)
RETURNS TABLE
AS
RETURN
(
WITH rec AS (
SELECT map_id,
[type_id],
CAST(name as nvarchar(max)) as name,
parent_id
FROM tblMapping
WHERE map_id = #map_id
UNION ALL
SELECT m.map_id,
m.[type_id],
r.name+'.'+m.name,
m.parent_id
FROM rec r
INNER JOIN tblMapping m
ON m.parent_id = r.map_id
)
SELECT *
FROM rec
);
GO
Then run this:
;WITH rec AS (
SELECT map_id,
[type_id],
CAST(name as nvarchar(max)) as name,
parent_id
FROM tblMapping
WHERE parent_id=0
UNION ALL
SELECT m.map_id,
m.[type_id],
r.name+'.'+m.name,
m.parent_id
FROM rec r
INNER JOIN tblMapping m
ON m.parent_id = r.map_id
)
SELECT t.role_group_id,
r.[type_id],
r.map_id,
r.name as [path]
FROM tblRoleGroup t
CROSS JOIN rec r
WHERE r.[type_id] = CASE WHEN t.desc_id IS NULL AND t.map_id = 0 THEN t.[type_id] ELSE NULL END
OR r.map_id = CASE WHEN t.desc_id = 1 THEN t.map_id ELSE NULL END
OR r.map_id IN (
SELECT map_id
FROM dbo.mapping (CASE WHEN t.desc_id = 0 THEN t.map_id ELSE NULL END)
)
ORDER BY role_group_id, r.[type_id], r.map_id
Will give you:
role_group_id type_id map_id path
1 1 1 A1
1 1 2 A2
1 1 3 A1.A3
1 1 4 A1.A3.A4
1 1 8 A1.A3.A4.A5
1 2 5 B1
1 2 6 B1.B2
1 2 7 B1.B2.B3
1 2 9 B4
2 1 3 A1.A3
2 2 6 B1.B2
2 2 7 B1.B2.B3
3 1 8 A1.A3.A4.A5
3 2 9 B4

I need 2 count values from single column to be in same row using Over () clause

I have the following Result from Select statement
UnitId UnitType GroupId
1 1 1
2 1 1
3 1 2
4 2 2
5 2 2
6 2 2
7 2 2
I need the following result for each group Id
GroupId CountBasedOnUnitType1 CountBasedOnUnitType2
1 2 0
2 1 4
Thanks in advance.
Try this
SELECT * FROM
(
SELECT GroupId,
UnitType
FROM Table1
) x
Pivot
(
Count(UnitType)
For UnitType in ([1], [2])
) p
Fiddle Demo
Output
GroupId 1 2
1 2 0
2 1 4
Does in necessarily need to have OVER?
select
GroupID,
sum(case when UnitType = 1 then 1 else 0 end) CountBasedOnUnitType1,
sum(case when UnitType = 2 then 1 else 0 end) CountBasedOnUnitType2
from table
group by GroupID

T-SQL Reverse Pivot on every character of a string

We have a table like below in an sql server 2005 db:
event_id staff_id weeks
1 1 NNNYYYYNNYYY
1 2 YYYNNNYYYNNN
2 1 YYYYYYYYNYYY
This is from a piece of timetabling software and is basically saying which staff members are assigned to an event (register) and the set of weeks they are teaching that register. So staff_id 1 isn't teaching the first 3 weeks of event 1 but is teaching the following 4....
Is there an easy way to convert that to an easier form such as:
event_id staff_id week
1 1 4
1 1 5
1 1 6
1 1 7
1 1 10
1 1 11
1 1 12
1 2 1
1 2 2
1 2 3
1 2 7
1 2 8
1 2 9
2 1 1
2 1 2
2 1 3
2 1 4
2 1 5
2 1 6
2 1 7
2 1 8
2 1 10
2 1 11
2 1 12
WITH cte AS
(
SELECT 1 AS [week]
UNION ALL
SELECT [week] + 1
FROM cte
WHERE [week] < 53
)
SELECT t.event_id, t.staff_id, cte.[week]
FROM your_table AS t
INNER JOIN cte
ON LEN(ISNULL(t.weeks, '')) >= cte.[week]
AND SUBSTRING(t.weeks, cte.[week], 1) = 'Y'
ORDER BY t.event_id, t.staff_id, cte.[week]