Selecting Records As Paired Parent Child - sql

Records are being saved as parent-child in the same table linked with pairkey column and then even parents are divided into two legs linked with scndleg column. That is, there will be two parent legs interlinked with scndleg column and each parent will have children having seqnno of parent in pairkey column.
Look at this fiddle
I need to select one complete batch as
Both legs of interlinked parents
UNION
All children of these two parents
and then the other batch following same pattern and so on shown in the fiddle

Edit New version of the query (link to SQLFiddle at the end):
SELECT
seqnno,
narration,
pairkey,
scndleg
FROM (
SELECT p.*, LEAST(seqnno, scndleg) related_leg_min_id
FROM pairs p
)
START WITH scndleg IS NOT NULL
CONNECT BY pairkey = PRIOR seqnno AND scndleg IS NULL
ORDER BY connect_by_root(related_leg_min_id), scndleg DESC NULLS LAST, pairkey
;
Output:
SEQNNO NARRATION PAIRKEY SCNDLEG
---------- ------------------------ ---------- ----------
1 1st leg parent 1 4
4 2nd leg parent 4 1
2 1st leg child 1
3 1st leg child 1
5 2nd leg child 4
6 2nd leg child 4
7 another 1st leg parent 7 10
10 another 2nd leg parent 10 7
8 another 1st leg child 7
9 another 1st leg child 7
11 another 2nd leg child 10
12 another 2nd leg child 10
SQLFiddle

Related

Get all of the low-level children of a node

I am struggling with the writing of a query for PostgreSQL. The table resembles a tree and every item can have n children.
I would like to get only and all the children of the lowest level(s) (which don't have any children by themselves) of a given element of the tree.
The structure:
CREATE TABLE items
(
ikey integer NOT NULL,
description character varying(255),
parent integer,
CONSTRAINT i_pk PRIMARY KEY (ikey),
CONSTRAINT i_relation FOREIGN KEY (parent)
REFERENCES items (ikey) MATCH SIMPLE
)
Some values of the table would look like this:
1 "Products" NULL --Parent
2 "Metal" 1
3 "Nails" 2
4 "Chains" 2
5 "Bicycle Chains" 4
6 "Shimano Bicycle Chains" 5
7 "Shimano Bicycle Chains" 5
8 "7mm chain, black" 4
9 "Wood" 1
10 "Cutting Boards" 8
11 "Cutting Board Holder" 8
Most of the solutions on SO deal with not very deep trees which have just 1-2 levels. Or it is known from which parent the children are required.
I would like to select all children of "Chains" (4), which would give the following result:
6 "Shimano Bicycle Chains" 5
7 "Shimano Bicycle Chains" 5
8 "7mm chain, black" 4
To be honest, recursive queries are not my strongest skill. I had the idea already to search upside down - getting all items first which are never used as parents and then going down, but this only shifts the problem to the point again that I have to go down recursively from the given parent which seems a bit over the top.
If you want to find all children items of an item in all levels you can write a recursive CTE. For example:
with recursive
n as (
select * from items where parent = 4 -- Children of "Chains"
union all
select i.*
from n
join items i on i.parent = n.ikey
)
select * from n
Result:
ikey description parent
----- ------------------------- ------
5 Bicycle Chains 4
8 7mm Chain Black 4
6 Shimano Bicycle Chains 1 5
7 Shimano Bicycle Chains 2 5
See running example at DB Fiddle.
You do not need a recursive query. Instead, you can simply select the rows with ikeys that do not occur as parents:
select i1.* from items i join items i1 on i.ikey = i1.parent where i.parent = 4 and
not exists (select 1 from items i2 where i2.parent = i1.ikey)
Another recursive CTE, with extras.
The base key that started the recursion & level of the tree.
WITH RECURSIVE RCTE_OFFSPRING AS (
SELECT ikey as base, 0 as lvl
, ikey, description, parent
FROM items
WHERE ikey = 4
UNION ALL
SELECT cte.base, cte.lvl + 1
, itm.ikey, itm.description, itm.parent
FROM items itm
JOIN RCTE_OFFSPRING cte
ON cte.ikey = itm.parent
)
SELECT *
FROM RCTE_OFFSPRING
WHERE lvl > 0
ORDER BY base, lvl, ikey
base
lvl
ikey
description
parent
4
1
5
Bicycle Chains
4
4
1
8
7mm chain, black
4
4
2
6
Shimano Bicycle Chains
5
4
2
7
Shimano Bicycle Chains
5
db<>fiddle here

BOM Explosion with Blanks

I have a simple BOM table that contains a parent and a child column.
Every row contains values. There are no blanks.
To bring that table into a BI-Tool I need to add blank values for the parents, like here shown:
As you can see, if an EntityKay has no parent key, then there should be a blank value.
How would you do that?
Example:
Current State:
Child Parent
4 1
5 1
6 2
7 3
8 3
9 3
Needed Result:
Child Parent
1
2
3
4 1
5 1
6 2
7 3
8 3
9 3
This query provides the missing keys, i.e. the parents, that are no childs are selected with the parent null
select distinct Parent Child, null Parent from bom
where Parent not in (select Child from bom)
order by 1;
CHILD PARENT
---------- ------
1
2
3
You must add those records (with an INSERT) to your table and probably update additionaly the description.
insert into bom (Child, Parent)
select distinct Parent Child, null Parent from bom
where Parent not in (select Child from bom)
Result
select * from bom;
CHILD PARENT
---------- ----------
4 1
5 1
6 2
7 3
8 3
9 3
2
3
1
To get the extended data without modifying the table use an UNION ALL of the ofiginal table with the query providing the missing part.
You may add also the names for the new rows using the DECODE as show below in the example
select
Child, Parent, name
from BOM union all
select distinct
Parent Child, null Parent,
decode(Parent,1,'North America',2,'Europa',3,'Asia')
from bom
where Parent not in (select Child from bom)

SQL products contain other

I have a table look like this
Parent Child
10 2
10 3
10 4
10 5
11 2
11 3
as you can see parent 10 also contain parent 11 and thats what I want to display in the table, I want to add to it a row with that data :
Parent Child
10 2
10 3
10 4
10 5
**10 11**
11 2
11 3
You can get parents that "contain" other parents using a self-join and aggregation:
with t as (
select t.*, count(*) over (partition by parent) as num_child
from yourtable
)
select tp2.parent, tp.parent
from t tp join
t tp2
on tp.child = tc2.child and tp.parent <> tp2.parent
group by tp.parent, tp2.parent, tp.num_child
having count(*) = tp.num_child -- all children match
(This version assumes no duplicate rows.)
You can then use insert to add these into the table.
Note: If two parents have the same children, two rows will be inserted.

How to define the number of levels in a hierarchy using sql?

My situation is the following. I have a table containing a product hierarchy. The following table is an extract of the dataset:
child parent
1 2
2 3
4 5
6 7
I want to add a column containing the depth (of the child) of the hierarchy. Something as follows:
child parent depth
1 2 2
2 3 1
4 5 1
6 7 1
How would I do that in oracle? Thank you!
Something like:
SELECT child, parent, level
FROM your_table
START WITH parent NOT IN ( SELECT child FROM your_table )
CONNECT BY parent = PRIOR child;
Outputs:
CHILD PARENT LEVEL
----- ------ -----
1 2 2
2 3 1
4 5 1
6 7 1

How to do a rollup of one table in SQL Server and have child tables rolled up to refer correctly to the rolled up parent rows in SQL Server

We have some tables in our database that pretty much grow infinitely so we are trying to create a task that will rollup old data on a periodic basis (probably daily) and remove the records that are contained in the rollup.
This is reasonably easy to do just using a GROUP BY. The catch is that are child tables that need to be rolled up as well and refer to the new completed parent table rows that they refer to and I have no idea how to do that without doing some really lame subqueries.
As an example say I start with the following data in the two tables:
Parent Table (ID is an IDENTITY column)
ID Type Amount
-- ---- ------
1 1 10.00
2 1 3.00
3 3 8.00
4 3 9.00
Child Table
ParentID Thing Qty
-------- ----- ---
1 8 3
1 6 6
2 8 4
2 5 3
3 8 2
3 5 1
4 5 4
First I would roll up the parent table into new rows that are grouped by Type and then the Amounts are summed together which would give the following:
ID Type Amount
-- ---- ------
5 1 13.00
6 3 17.00
The query to create the above data in Parent the query would look something like the following:
INSERT INTO Parent (Type, Amount)
SELECT Type, SUM(Amount) AS Amount
FROM Parent
GROUP BY Type
For the child table I want to do something similar, except grouping by "Thing" and summing Quantity with the ParentID referring to the newly created Parent that corresponds to the original Parent. This would create something like the following:
ParentID Thing Qty
-------- ----- ---
5 8 7
5 5 3
5 6 6
6 5 5
6 8 2
This query would look something similar to the following but I don't know how to get the ParentID or how to link to the Parent table:
INSERT INTO Child (ParentID, Thing, Qty)
SELECT ?, Thing, SUM(Qty) AS Qty
FROM Child
INNER JOIN Parent
ON ? = ?
GROUP BY ?, Thing
I would assume that this is something that happens somewhat frequently so does anyone know what the correct way to handle this situation is?
First Table:
Declare #max int = (Select MAX(ID) from parent)
Select #max
Select #max+R ID,type,Amount
from
(
Select type,sum(amount) 'Amount',ROW_NUMBER() over(order by type) 'R'
from parent
group by Type
) R
Second Table:
Select #max+TYPE 'ParentID',[group],sum(Qty) 'Qty'
from child
join parent
on id = parentid
group by type,[group]
order by [parentid],[group]