I have a table as follows
--------------------------------
ChildId | ChildName | ParentId |
--------------------------------
1 | A | 0 |
--------------------------------
2 | B | 1 |
--------------------------------
3 | C | 1 |
--------------------------------
I would like to select data as -
---------------------------------------
Id | Name | Childs |
---------------------------------------
1 | A | 2 |
---------------------------------------
2 | B | 0 |
---------------------------------------
3 | C | 0 |
---------------------------------------
The pseudo SQL statement should be like this-
SELECT ChildId AS Id, ChildName as Name, (Count (ParentId) Where ParentId=ChildId)
Any Help?
This will do the trick:
select t1.childid, t1.childname, count(*) as childs
from table t1
join table t2 on t1.childid = t2.parentid
group by t1.childid, t1.childname
Something like this?
SELECT ChildId AS Id, ChildName as Name, (SELECT COUNT(*) FROM TestCountOver T WHERE T.ParentID = O.ChildID) FROM TestCountOver O
but that would give you all the nodes plus children who shouldn't be part of the hierarchy
If you want only nodes with children then use a cte
;WITH CTE AS (
SELECT ChildId AS Id, ChildName as Name, (SELECT COUNT(*) FROM TestCountOver T WHERE T.ParentID = O.ChildID) Cnt FROM TestCountOver O
)
SELECT *
FROM CTE
WHERE Cnt > 0
If there is only one level you can use the approach in your pseudo code. It should look like this:
SELECT
ChildId AS Id,
ChildName as Name,
(select Count(ParentId) from t t_inner Where ParentId=t_outer.ChildId) children
from t t_outer
-- optionally where clause to limit result to parents that have children
where exists (select 1 from t where ParentId in (t_outer.ChildId))
but if there can be more than one level you can solve it using a recursive query if you want the total number of children for a parent (including grand-children etc).
Related
I have a table that looks like this:
ID | PARENT_ID
--------------
0 | NULL
1 | 0
2 | NULL
3 | 1
4 | 2
5 | 4
6 | 3
Being an SQL noob, I'm not sure if I can accomplish what I would like in a single command.
What I would like is to start at row 6, and recursively follow the "history", using the PARENT_ID column to reference the ID column.
The result (in my mind) should look something like:
6|3
3|1
1|0
0|NULL
I already tried something like this:
SELECT T1.ID
FROM Table T1, Table T2
WHERE T1.ID = 6
OR T1.PARENT_ID = T2.PARENT_ID;
but that just gave me a strange result.
With a recursive cte.
If you want to start from the maximum id:
with recursive cte (id, parent_id) as (
select t.*
from (
select *
from tablename
order by id desc
limit 1
) t
union all
select t.*
from tablename t inner join cte c
on t.id = c.parent_id
)
select * from cte
See the demo.
If you want to start specifically from id = 6:
with recursive cte (id, parent_id) as (
select *
from tablename
where id = 6
union all
select t.*
from tablename t inner join cte c
on t.id = c.parent_id
)
select * from cte;
See the demo.
Results:
| id | parent_id |
| --- | --------- |
| 6 | 3 |
| 3 | 1 |
| 1 | 0 |
| 0 | |
dbo.Tags
---------------
[TagsId]
dbo.TagsDetail
----------------
[TagsDetailId]
[TagsId]
[TagsGroupId]
dbo.TagsGroup (hierarchical table with 2 level)
----------------
[TagsGroupId]
[ParentId]
Tags
+--------+
| Tagsld |
+--------+
| 1 |
| 2 |
+--------+
TagsDetails
+-------------+-----------+
| Tagsld |TagsGroupId|
+-------------+-----------+
| 1 | 1 |
| 2 | 2 |
+-------------+-----------+
TagsGroup
+-------------+-----------+
| TagsGroupId | ParentId |
+-------------+-----------+
| 1 | null |
| 2 | null |
| 3 | 1 |
+-------------+-----------+
Input TagGroupsId = 2 => all taggroup(1, 2, 3)
How can I select all related TagsGroupIds by input one #TagsGroupId?
I tried to solved by selecting all TagsDetailIds by #TagsGroupId so I find all TagsIds and from TagsIds. I found all TagsDetailIds and then get all relate TagsGroupIds and it's descendants and on each TagsGroupId, I started a loop again.
I don't know where I can stop to make sure I have selected all TagsGroupId.
Note: Using plurals is not typically how this is done -- so the column should be called TagId not TagsId and the table should be called TagGroup not TagsGroup. Just easier this way. It has no effect but that is the style convention everyone uses.
So as I understand it, a tag group can have up to two parents and can have children and grand children.
You can do it all in one query (with sub queries and joins) but I think a CTE will make the logic easier.
WITH Parent AS
(
SELECT TD.TagId
FROM TagGroup TG
JOIN TagDetail ON TD.TagGroupId = TG.ParentId
WHERE TG.TagGroupId = #TagGroupId
), GrandParent AS
(
SELECT TD.TagId
FROM TagGroup TG
JOIN TagDetail ON TD.TagGroupId = TG.ParentId
WHERE TG.TagGroupId = (SELECT TagId FROM Parent)
), Child AS
(
SELECT TD.TagId
FROM TagGroup TG
JOIN TagDetail ON TD.TagGroupId = TG.TagGroupId
WHERE TG.ParentId = #TagGroupId
), GrandChild AS
(
SELECT TD.TagId
FROM TagGroup TG
JOIN TagDetail ON TD.TagGroupId = TG.TagGroupId
WHERE TG.ParentId = (SELECT TagId FROM Child)
)
SELECT TagId
FROM Parent
UNION
SELECT TagId
FROM GrandParent
UNION
SELECT TagId
FROM Child
UNION
SELECT TagId
FROM GrandChild
How to know all possible Parent and Child Rows against specific Id?
e.g. have following table:
MyTable:
-----------------------------------------------------
| Id | PId | Description |
-----------------------------------------------------
| 1 | NULL | A is Parent |
| 2 | 1 | B is Child of A |
| 3 | 2 | C is Child of B |
| 4 | NULL | D is Parent |
| 5 | NULL | E is Parent |
| 6 | 5 | F is Child of E |
-----------------------------------------------------
want to know all possible parent and child when pass spesific id
e.g.
CASE-01:
When #MyLookupId=2 OR #MyLookupId=1 OR #MyLookupId=3 One of from them Then Result Should Be,
-------
| Id |
-------
| 1 |
| 2 |
| 3 |
-------
CASE-02:
When #MyLookupId=4 Then Result Should Be,
-------
| Id |
-------
| 4 |
-------
CASE-03:
When #MyLookupId=6 Then Result Should Be,
-------
| Id |
-------
| 5 |
| 6 |
-------
Here is SQL for table:
IF OBJECT_ID('tempdb.dbo.#MyTable', 'U') IS NOT NULL DROP TABLE #MyTable;
SELECT * INTO #MyTable FROM (
SELECT (1)Id, (NULL)PId, ('A IS Parent')Description UNION ALL
SELECT (2)Id, (1)PId, ('B IS Child of A')Description UNION ALL
SELECT (3)Id, (2)PId, ('C IS Child of B')Description UNION ALL
SELECT (4)Id, (NULL)PId, ('D IS Parent')Description UNION ALL
SELECT (5)Id, (NULL)PId, ('E IS Parent')Description UNION ALL
SELECT (6)Id, (5)PId, ('F IS Child of E')Description ) AS tmp
SELECT * FROM #MyTable
You could use recursive cte
-- temp returns full tree of each rootId (parentid = null)
;WITH temp AS
(
SELECT sd.Id, sd.PId, sd.Id AS RootId
FROM #MyTable sd
WHERE sd.PId IS NULL
UNION ALL
SELECT sd.Id, sd.PId, t.RootId
FROM temp t
INNER JOIN #MyTable sd ON t.Id = sd.PId
)
SELECT t2.Id
FROM temp t
INNER JOIN temp t2 ON t2.RootId = t.RootId
WHERE t.Id = #Id
OPTION (MAXRECURSION 0)
Demo link: http://rextester.com/RAITMT72805
The answer given by TriV works, but requires a calculation of the entire hierarchy of your source table each time the query is run, which may not perform well at larger scale.
A more narrow approach is to find the Parent and Child records that only relate to the ID you are searching for:
declare #t table(ID int, PID int);
insert into #t values(1,null),(2,1),(3,2),(4,null),(5,null),(6,5);
declare #ID int = 2;
with c as
(
select ID
,PID
from #t
where ID = #ID
union all
select t.ID
,t.PID
from #t t
join c
on(t.PID = c.ID)
)
,p as
(
select ID
,PID
from #t
where ID = #ID
union all
select t.ID
,t.PID
from #t t
join p
on(t.ID = p.PID)
)
select ID
from p
union all
select ID
from c
where c.ID <> #ID
order by ID;
Output:
ID
````
1
2
3
I am working on recursive query which take table with parent-child relation
ID | ParentID | description
1 | null | Company
2 | 1 | Department
3 | 2 | Unit1
4 | 2 | Unit2
5 | 4 | Unit3
6 | 4 | Unit4
and is suppose to display following result:
ID | ParentID | description
1 | null | Company
2 | 2 | Department
3 | 2 | Unit1
4 | 2 | Unit2
5 | 2 | Unit3
6 | 2 | Unit4
Of course the number of Deparments and units is larger. The basic quest is to display parentId for parent and its child level. Do you have any ideas how to achive this?
So far I only made this query
WITH cte (ID, ParentID, description)
AS
(
SELECT ID, ParentID, description
FROM T1
UNION ALL
SELECT e.ID, e.ParentID, e.description
FROM T2 AS e
JOIN cte ON e.ID = cte.ParentID
)
SELECT
cte.ID, cte.ParentID, cte.description
FROM cte
cte.ParentID is not null
Your syntax isn't quite right, but the idea is in the right direction. In the end, you want to fetch the rows where the parent's parent is NULL. This might work (it is untested):
WITH cte(ID, ParentID, description, lev) AS
(SELECT ID, ParentID, description, 1 as lev
FROM table T1
UNION ALL
SELECT cte.ID, e.ParentID, cte.description, cte.lev + 1
FROM table e JOIN
cte
ON e.ID = cte.ParentID
)
SELECT cte.ID, cte.ParentID, cte.description
FROM cte left outer join
table t
on cte.ParentId = t.ParentId
WHERE t.ParentID is null;
I've tried to strip this problem down the the bare bones; I hope I've still captured the essence of what I'm trying to achieve in the original query!
Code to generate the tables and data can be found here.
SQL flavour is Microsoft SQL Server 2000 (although I've been running this stripped down test case on MySQL)
The original table
+-----------+----------+----------+
| master_id | slave_id | distance |
+-----------+----------+----------+
| 1 | 1 | 0.1 |
| 1 | 3 | 10 |
| 2 | 2 | 3 |
| 3 | 2 | 2 |
+-----------+----------+----------+
Description of what is required
I would like to select slave_id master_id pairs with MIN(distance) with no duplicates of either master_id or slave_id.
The desired results table
+-----------+----------+----------+
| master_id | slave_id | distance |
+-----------+----------+----------+
| 1 | 1 | 0.1 |
| 3 | 2 | 2 |
+-----------+----------+----------+
My Attempt
SELECT
join_table.master_id,
join_table.slave_id,
join_table.distance
FROM join_table
INNER JOIN
(
SELECT
slave_id,
MIN(distance) AS distance
FROM join_table
GROUP BY slave_id
) AS self_join
ON self_join.slave_id = join_table.slave_id
AND self_join.distance = join_table.distance
What's wrong with my attempt
This query produces duplicates of master_id
Any help will be very much appreciated.
This should give the correct result:
select distinct t.master_id,
t.slave_id,
t.distance
from join_table t
inner join
(
SELECT ID, min(Distance) dist
FROM
(
SELECT master_ID ID, MIN(distance) AS Distance
FROM join_table
GROUP BY master_ID
UNION
SELECT slave_ID ID, MIN(distance) AS Distance
FROM join_table
GROUP BY slave_ID
) src
GROUP BY ID
) md
on t.distance = md.dist
and (t.master_id = md.id or t.slave_id = md.id)
See SQL Fiddle with Demo
If I got you right, here is what I would do:
SELECT DISTINCT t.master_id
,t.slave_id
,t.distance
FROM your_table t
INNER JOIN
(
SELECT master_id id, min(distance) distance
FROM your_table
GROUP BY master_id
UNION
SELECT slave_id id, min(distance) distance
FROM your_table
GROUP BY slave_id
) sub
ON (sub.id = t.master_id AND sub.distance = t.distance)
OR (sub.id = t.slave_id AND sub.distance = t.distance)