Parent - child sql query with in a single table - sql

I've a table:
Id | Name | ParentID
I want to select records whose parentid not equal to zero, with parent record(parent record have parentid = 0, but some parent record don't have child record I want to skip them )

Try this:
SELECT child.Id,
child.Name,
child.ParentId,
parent.Name as ParentName
FROM your_table child
JOIN your_table parent ON child.ParentId = parent.id;

Check this one:
select * from child c,parent p where c.ID=P.ParentID and c.ParentID !=0

Related

Keep only one record from left table

I need to get records after inner join without duplicate data from left table.
Parent table :
Parent id parent name
1 Douglas
Child table :
Parent id child name
1 George
1 Michael
With classic Oracle Inner join I get this :
Parent id parent name child name
1 Douglas George
1 Douglas Michael
But I need this result:(i need null values instead of parents names)
Parent id parent name child name
1 Douglas George
Null Null Michael
Of course, there are more parents and children.
Use row_number() or lag() or lead(), like here:
select case when rn = 1 then parent_id end parent_id,
case when rn = 1 then parent_name end parent_name,
child_id, child_name
from (select p.parent_id, p.parent_name, c.child_id, c.child_name,
row_number() over (partition by p.parent_id order by c.child_id) rn
from parents p join children c on p.parent_id = c.parent_id)
rextester demo
PARENT_ID PARENT_NAME CHILD_ID CHILD_NAME
---------- ----------- ---------- ----------
1 Douglas 1 George
2 Michael
You want to do a right join on child id
select p.parentid,p.parentname,c.childname
from parent p
right join child c
on p.parentid=c.childid
One way of doing this is with a CURSOR EXPRESSION:
select parent_id
, parent_name
, cursor ( select child_id
, child_name
from child
where child.parent_id = parent.parent_id )
from parent
How well this renders depends on the client you use to run it. Some handle the output better than others.
Alternatively you can treat it as a display issue. For instance, in SQL*Plus you could use BREAK ON parent_id ON parent_name to suppress repeating values. Find out more.
select parent.parent_id
, parent.parent_name
, child.child_id
, child.child_name
from parent
join child
on child.parent_id = parent.parent_id
order by parent.parent_id, child.child_id;
To make this work you have to have ordering.
"It seems more complicated than I thought. Is there other way without Cursor?"
That's because result sets are meant to be flat not jagged. Tweaking the query to implement display features often results in clunky or verbose SQL.
Talking of which, here's another solution for you:
with cte as (
select parent.parent_id
, parent.parent_name
, child.child_id
, child.child_name
, row_number() over (partition by parent.parent_id
order by child.child_id ) as prn
, row_number() over (order by parent.parent_id , child.child_id ) as rn
from parent
join child
on child.parent_id = parent.parent_id
)
select case when prn = 1 then parent_id else null end as parent_id
, case when prn = 1 then parent_name else null end as parent_name
, child_id
, child_name
from cte
order by rn
This generates two row numbers, one to track the parents, one to sort the entire row set.

sql - How to return NULL row from left table for each parent even when child records exist

I have 2 tables with a parent-child relation. I'd like to return a row with NULL child values for parents that have children, in addition to the child records.
For example, for tables parent and child:
SELECT parent.parentid, childid
FROM parent
LEFT JOIN child
ON parent.parentid=child.parentid
For a parent parentA with children childA1, childA2, I'd like a result:
parentA, NULL
parentA, childA1
parentA, childA2
A normal LEFT JOIN will not return the first row. A UNION query works, but I'm wondering if there is a simpler/better query, using standard SQL for Oracle and SQL Server. My UNION query is:
SELECT parent.parentid, childid
FROM parent
INNER JOIN child ON parent.parentid=child.parentid
UNION
SELECT parent.parentid, NULL
FROM parent
I think your query is better written as:
SELECT p.parentid, childid
FROM parent p INNER JOIN
child c
ON p.parentid = c.parentid
UNION ALL
SELECT p.parentid, NULL
FROM parent p;
That is UNION ALL is better than UNION, because UNION has additional overhead for removing duplicate values. If you can have duplicates in parent, just use SELECT DISTINCT in the second query.
Also, you might want to add an ORDER BY to get results in order the question seems to specify:
ORDER BY parentid, (CASE WHEN child is NULL then 0 else 1 end), chile
An alternative way of doing it would be
SELECT parent.parentid,
childid
FROM parent
LEFT JOIN child
ON parent.parentid = child.parentid
GROUP BY GROUPING SETS( ( parent.parentid ), ( parent.parentid, childid ) )
HAVING (childid IS NOT NULL) OR GROUPING(childid) =1
ORDER BY parentid ASC,
GROUPING(childid) DESC
If you only want the row for parents with children you should use an inner join
SQL Fiddle - Oracle
SQL Fiddle - SQL Server

Query that selects the sum of all records that are referenced in another table

I have two tables, parent(id, name, child_id) and child(id, name, number) - not all parents may have childs and not all childs may have parents. I need a query that selects the sum of all records in child table and also selects the sum of only those records that have a parent and those that dont - that is determined by parent tables child_id column. How can this be done?
select
sum(c.number) AS sum AS a,
sum(all_child_records_that_have_a_parent) AS b,
sum(all_child_records_that_do not have a parent) AS c /*do not use a-b if possible*/
from
child c
The "all_child_records_that_have_a_parent" is the one i cant figure out :)
all_child_records_that_do not have a parent:
SELECT *
FROM child
WHERE id NOT IN (SELECT child_id FROM parent)
You can select distinct child ids from the parent table and outer join these to your child table. Then check for NULL.
select
sum(c.number) AS sum_all_c,
sum(case when x.child_id is not null then c.number end) AS sum_c_with_parent,
sum(case when x.child_id is null then c.number end) AS sum_c_without_parent
from child c
left outer join (select distinct child_id from parent) x on x.child_id = c.id;

Counting a root's children in SQL

Let's say I have a table with 3 columns:
item ID 'ID'
parent ID 'ParentID'
item name 'Title'
Now, how should I count how many children a Root has?
SELECT COUNT(*)
FROM T
WHERE ParentID = #ParentID
If you want descendants not just immediate children you would need a recursive CTE.
;WITH R AS
(
SELECT ID
FROM T
WHERE ParentID = #RootID
UNION ALL
SELECT T.ID
FROM T
JOIN R ON R.ID = T.ParentID
)
SELECT COUNT(*)
FROM R

SQL: Selecting Where Latest Sub Child

I have a few model which looks a little something like this: Parent has a 1-2-M relationship with Child, and Child has a 1-2-M relationship with Sub-Child.
Parent
------
Parent_ID
Child
-----
Child_ID,
Parent_ID
Sub-Child
---------
Child_ID,
Version_Number (numeric),
Sent (date),
Void (date)
I want a query which returns a list of unique parent_id's where the latest version (judged by the version_number) of a related sub-child is 'sent' == null, but 'void' != null.
I've been chewing this over in my head and can't figure things out.
Any advice would be greatly appreciated.
Thanks,
Robert
It'll be something like:
;WITH CTE_LatestSubChildren AS
(
SELECT Parent_ID, Latest_Version_Number = max(sc.Version_Number)
FROM
Child c
JOIN [Sub-Child] sc on c.Child_ID = sc.Child_ID
GROUP BY c.Parent_ID
)
SELECT
ParentID
FROM
CTE_LatestSubChildren lsc
JOIN Child c
on lsc.Parent_ID = c.Parent_ID
JOIN [Sub-Child] sc
ON sc.Child_ID = c.Child_ID
AND sc.version_number = lsc.Latest_Version_Number
AND sc.Sent IS NULL
AND sc.Void IS NOT NULL
Note that this may require amendments as its not tested, and its not completely clear what should happen about multiple child records where the latest version is the same.
I'm not where I can test this, but it sounds like you'll need a subquery to pull the max version numbers of each child, then a self-join to get the rest of the sub-child information. Something like this is what I'm thinking:
SELECT DISTINCT
Parent_ID
FROM
Parent JOIN Child
ON Parent.Parent_ID = Child.Parent_ID
JOIN (
SELECT Child_ID, MAX(Version_Number)
FROM Sub-Child
GROUP BY Child_ID ) AS MaxSubchild
JOIN Sub-Child
ON Sub-Child.Child_ID = MaxSubchild.Child_ID AND
Sub-Child.Version_Number = MaxSubchild.Version_Number
WHERE
SUb-Child.Sent IS NULL AND
Sub-Child.Void IS NOT NULL;
Start by getting the max version by child_id:
select child_id, max(version_number) as version_number
from subchild
group by child_id
Then join it as a subquery, with subchild and child, and apply your where condition.
Or, without subqueries, try,
SELECT DISTINCT p.parent_id
FROM sub_children sc
LEFT JOIN children c ON sc.parent_id = c.child_id
LEFT JOIN parents p ON c.parent_id = p.parent_id
WHERE sc.sent == null, but sc.void != null
You can also use Rank():
SELECT DISTINCT TOP 100 PERCENT ST.Parent_ID
FROM
(
SELECT RANK() OVER (PARTITION BY C.Parent_ID ORDER BY SC.Version_Number DESC) AS [RANK],
C.Parent_ID, SC.Sent, SC.Void
FROM Child C
INNER JOIN Sub_Child SC ON C.Child_ID = SC.Child_ID
) ST
WHERE [RANK] = 1
AND [Sent] IS NULL AND [Void] IS NOT NULL