Getting all the children of a parent using MSSQL query - sql

I have the following data in my database:
Parent Child
101 102
101 103
101 104
101 105
101 106
My parameter is 106. And using the parameter I want to retrieve all the other children under its parent which is 101. I tried using the recursive method but it didn't work given the following data. Is there another way to formulate a query?

Assuming you want to get siblings of the value #p0, you can use a simple self-join:
SELECT p.Child
FROM Table1 c
INNER JOIN Table1 p ON c.Parent = p.Parent
WHERE c.Child = #p0
AND p.Child <> #p0
The not-equal clause here makes sure you get siblings not including the value you searched for. Remove it as necessary.
SQL Fiddle example
Since you mention recursion though, perhaps you want the entire tree starting at the parent of the value #p0. In which case, you can use a recursive CTE:
WITH parent AS (
SELECT Parent
FROM Table1
WHERE Child = #p0
), tree AS (
SELECT x.Parent, x.Child
FROM Table1 x
INNER JOIN parent ON x.Parent = parent.Parent
UNION ALL
SELECT y.Parent, y.Child
FROM Table1 y
INNER JOIN tree t ON y.Parent = t.Child
)
SELECT Parent, Child
FROM tree
SQL Fiddle examples using your data and
with additional data to demonstrate the recursive CTE

SQL Authority has a blog with a very nice explanation of how to perform a Hierarchical Query using a Recursive CTE
http://blog.sqlauthority.com/2012/04/24/sql-server-introduction-to-hierarchical-query-using-a-recursive-cte-a-primer/
Regards

select child
from my_table T1
where exists (select 1 from my_table T2 where child = #parameter and T1.parent = T2.parent)

WITH parent AS (
SELECT Parent
FROM Table1
WHERE Child = #p0
), tree AS (
SELECT x.Parent, x.Child
FROM Table1 x
INNER JOIN parent ON x.Parent = parent.Parent
UNION ALL
SELECT y.Parent, y.Child
FROM Table1 y
INNER JOIN tree t ON y.Parent = t.Child
)
SELECT Parent, Child
FROM tree

Related

SQL query to return a chain

I have a table that tracks changes. One column is called beforename and the other aftername.
Some sample data might be:
Parent
Child
a
b
b
c
c
d
I am trying to write a query that will self reference itself in such a way as to return the changes ie:
a -> b -> c -> d (the arrows are just for notation here)
Is this possible to do in SQL?
My database is SQL Server
You could use a recursive common table expression (CTE);
WITH cte(Root, Level, Parent, Child) AS (
SELECT Parent, 0, Parent, Child FROM Table1
WHERE Parent NOT IN (SELECT Child FROM Table1)
UNION ALL
SELECT cte.Root, cte.Level + 1, t1.Parent, t1.Child
FROM cte
JOIN Table1 t1
ON cte.Child = t1.Parent AND cte.Level < 10
)
SELECT * FROM cte ORDER BY Root, Level;
Basically, a recursive CTE uses a base case (find all starting points). THis one uses;
SELECT Parent, 0, Parent, Child FROM Table1
WHERE Parent NOT IN (SELECT Child FROM Table1)
...which finds all parents, that is rows where the parent is never mentioned in the table as a child. It then sets those parent as a "Root" and sets level to 0.
It then proceeds to find the child rows for that root using;
SELECT cte.Root, cte.Level + 1, t1.Parent, t1.Child
FROM cte
JOIN Table1 t1
ON cte.Child = t1.Parent AND cte.Level < 10
...which basically just finds the next child (a row which has this rows child as a parent) while keeping the root and increasing level by 1.
It also limits the recursion to 10 levels just in case there is a loop in the data.
A dbfiddle to test with

SQL - return a value referenced by initial value from same table

I'm sure this has been asked before, but I can't seem to find any questions that help.
Here's an example of a table:
ID Name Parent ID
---------------------------
1 Ice cream 3
2 Chips 4
3 Sweets null
I'm trying to figure out how to write a single query which, given ID=1, will return me rows 1 and 3. Is this possible without making two queries?
Also, is there a way to return the information of the parent as a custom column? So, rather than returning 2 rows, returning the row where id=1 with parent_id=3 added on?
You can use union all and exists:
select * from mytable where parent_id = 3
union all
select t.*
from mytable t
where exists (select 1 from mytable t1 where t1.parent_id = t.id and t.parent_id = 3)
If you want to do this over multiple levels of hierarchy, then you would typically use a recursive query. The syntax slightly varies accross databases (and not all of them support recursion), but the idea is:
with recursive cte as (
select * from mytable where parent_id = 3
union all
select t.*
from cte c
inner join mytable t on t.parent_id = c.id
)
select * from cte
This is how a straight up noob would do it. Hold tight for someone to give a better way
SELECT ID, Name, Parent_ID
FROM table
WHERE ID = 1
UNION
SELECT ID, Name, Parent_ID
FROM table
WHERE ID = (SELECT Parent_ID FROM table WHERE ID = 1)
Are you looking for something like this?:
select child.ID, child.Name, parent.ID as ParentId, parent.Name as ParentName
from T child left outer join T parent on parent.Id = child.parent_id;

Simple Recursive Query child to last parent

I need to retrieve the last (or first) id of a child's parent.
Example:
ID PARENT_ID
----------------
1 NULL
2 1
3 2
So if I search the parent id of id=3 I would have 1 as result.
I tried this but it gives me the same id...
with
tree(id)
as
(
select id
from myTable
where id = 3
union all
select t.id
from myTable t
inner join tree on tree.id = t.father_id
)
select *
from tree;
I already saw examples here and on several websites ;)
You've got some inconsistent naming here. But anyway, your CTE needs to include the parent_id too.
Like this:
with
tree(id,parent_id)
as
(
select id, parent_id
from myTable
where id = 3
union all
select t.id, t.parent_id
from myTable t
inner join tree on t.id = tree.parent_id
)
select *
from tree;

Table self related query

I have a table which has self relationship:
id -- parentId columns
I need a query to get the parent row where the parentId is null, but I couldn't figure out the proper way of doing this.
select * from table1 where id = parentId;
Apparently this is not working, it will just give the direct parent.
Any help
"Get the parent row where the parentId is null" makes no sense, but in case you actually meant "get the parent row until the parentId is null", then this recursive CTE should do the trick:
WITH cte AS (
SELECT * FROM table1 WHERE id = 7
UNION ALL
SELECT table1.* FROM table1 JOIN cte ON table1.id = cte.parentId
)
SELECT * FROM cte
This returns the row with id = 7 and all its ancestors recursively. Replace 7 according to your needs.
SELECT *
FROM table1 AS A
LEFT JOIN table1 as B
ON B.ID = A.parentID
WHERE B.parentID IS NULL

How do I use a column value in a substrings where clause

03-30 13:17]
I'm trying to use a t-sql against SQL-Server 2005 with asp 3.0. What I want to do is first select all rows that match a certain condition and then I want to know how how many children are connected to that row based on it's ChildID.
This can of course be done by just doing two queries against the db one to get the matching rows for the Parent and one for each row that was found to know how many children have that as Parent.
I have two tables, table1 contains parents and children and table2 contains the information and the id here is ofcourse the id that is saved in parent and children in table1.
Now I want to first find all the children to a certain parent, and in the same sql-statement I want to know how many children is connected to each child.
So Parent 807 has two children, 808 and 809. 808 has 5 children and 809 has 72 children, how can I with one statement get both the information of children 808 and 809 and the numer of children connected to each of them.
My SQL looks like this (gets the children to parent 807)
SELECT Parent, Child, ID, FieldX, FieldY
FROM Tabel1 INNER JOIN Tabel2 ON Parent = ID
WHERE (Parent = 807)
The statement I use to get the numer of children connected to f.ex. 808 is as follows.
SELECT COUNT(*) AS AntalPoster
FROM Tabel1 INNER JOIN Tabel2 ON Child = ID
WHERE (Parent = 808)
What I would like to do is the following, but I would like to substitute the value 808 with the value each record gives me for the child aka SearchID.
SELECT Parent, Child AS SearchID, ID, FieldX, FieldY,
(SELECT COUNT(*) AS [Antal sidor]
FROM Tabel1 INNER JOIN Tabel2 ON Child = ID
WHERE (Parent = 808)) AS AntalPoster
FROM Tabel1 INNER JOIN Tabel2 ON Child = ID
WHERE (Parent = 807)
The problem I get is that "Invalid column name 'SearchID'", what I can understand is that I can't get the value that I find in SerachID to be used as a value in the next SQL-statements where clause.
Is this possible, and if so how?
Thanks in advance.
So, I understand, basically Table1 contains hierarchy information, and Table2 details.
Assuming that, here's my approach:
SELECT
h.Parent,
h.ChCount,
d.* /* you may want to expand it to a specific Table2 column list */
FROM (
/* first, get the children and their child counts */
SELECT
p.Parent,
p.Child,
COUNT(*) AS ChCount
FROM Table1 p
INNER JOIN Table1 c ON p.Child = c.Parent
GROUP BY p.Parent, p.Child
WHERE p.Parent = 807
) h
/* next, get the children's details */
INNER JOIN Table2 d ON h.Child = d.ID
Now I want to first find all the children to a certain parent, and in the same sql-statement I want to know how many children is connected to each child.
This is a way to do that.
declare #Table1 table (Table1ID int, ParentID int)
-- Root
insert into #Table1 values(807, null)
-- Children to 807
insert into #Table1 values(808, 807)
insert into #Table1 values(809, 807)
-- Children to 808
insert into #Table1 values(810, 808)
-- Children to 809
insert into #Table1 values(811, 809)
insert into #Table1 values(812, 809)
select
T1.*,
(select count(*)
from #Table1 as T2
where T1.Table1ID = T2.ParentID) as ChildCount
from #Table1 as T1
where T1.ParentID = 807
Result
Table1ID ParentID ChildCount
----------- ----------- -----------
808 807 1
809 807 2
Replace
WHERE (Parent = SearchID))
by
WHERE (Parent = ParentID))
But you're better of using
SELECT Parent, Child, ID, FieldX, FieldY, COUNT(*) AS AntalPoster
FROM Tabel1 INNER JOIN Tabel2 ON Child = ID
WHERE (Parent = [ParentID])
GROUP
BY Parent, Child, ID, FieldX, FieldY;
If you define a "alias" for a column you can't use this name inside the query earlier than within a group by or order by clause.
As is your example SearchID is just a name for column Child you should use WHERE (PARENT = Child)
You're kinda close.
SELECT Parent_ID, COUNT(*) AS AntalPoster FROM Tabel1 INNER JOIN Tabel2 ON Child = ID
Group by Parent_ID
Now I don' quite understand from reading your question what the 'ID' field is called...but the results of this query should give the Parent_ID along with the count of the number of child records (If I've read your setup corectly). Join to that subquerty to get the count.
SELECT Parent, Child.AntalPoster, ID, FieldX, FieldY
FROM Tabel1 INNER JOIN Tabel2 ON Parent = ID
inner join (SELECT Parent_ID, COUNT(*) AS AntalPoster FROM Tabel1 INNER JOIN Tabel2 ON Child = ID Group by Parent_ID) child on child.id = t1.ID
WHERE (Parent = 807)
Whats really confusing me in your example...if I'm still off with what you're going for...quickly giving us the schema would help. Is the table setup so it has Parent, Child, ID? If so, how does the work? I'd expect Parent_ID, Child_ID...bit confused on the third "ID" column, what does it hold thats unique from the parent,child columns that already exist?.
In any case, the logic is setup a subquery so it reads Key , Count(1). Then join to that subquery on the Key to obtain the count value the subquery returns.