How to output parent child relationships within tables in sql? - sql

I have Table1 which shows the child and parent relationships between products. How to I get the output table with sql? Basically, Input table shows that B is a child of A and B1 and B2 are child of B. The output would need to show that as well, and also that B1 and B2 are child of A.

I believe what you need is hierarchical queries.
As an example, you could do:
SELECT childproduct, parentproduct
FROM product_table
START WITH parentproduct = 'Product A'
CONNECT BY PRIOR childproduct = parentproduct;
Note: This assumed that you know the root (top level) element is 'Product A'. Although it may work without it too.

The answer to your problem is shown in this sqlfiddle: http://sqlfiddle.com/#!4/87657/61
You do need to use a Hierarchical Query as shown below:
SELECT ChildProduct, CONNECT_BY_ROOT ParentProduct
FROM table_name
WHERE LEVEL >= 1
CONNECT BY PRIOR ChildProduct = ParentProduct
| CHILD | CONNECT_BY_ROOTPARENT |
|------------|-----------------------|
| Product B | Product A |
| Product B1 | Product A |
| Product B2 | Product A |
| Product C | Product A |
| Product D | Product A |
| Product D1 | Product A |
| Product E1 | Product A |
| Product E2 | Product A |
| Product B1 | Product B |
| Product B2 | Product B |
| Product D1 | Product D |
| Product E1 | Product D |
| Product E2 | Product D |
| Product E1 | Product D1 |
| Product E2 | Product D1 |

Related

Identifying heirarchical groupings from a Parent-Child associaiton list in SQL

I am trying to identify groupings of accounts from a Parent-Child association table in SQL. Rather than a big hierarchy tree, I am dealing with many small trees and I need to identify each Tree as a unique Group in order to label related accounts.
I have two tables, a table of all Unique ID's:
+------+-------+
| ID | Group |
+------+-------+
| A | NULL |
| B | NULL |
| C | NULL |
| etc. | NULL |
+------+-------+
And a Table showing Parent - Child association between them:
+--------+-------+
| Parent | Child |
+--------+-------+
| A | D |
| A | E |
| B | F |
| B | G |
| B | C |
| C | H |
+--------+-------+
I Need to Fill the Group field of my first table so that I can identify all accounts which have a direct or indirect relationship eg:
+----+-------+
| ID | Group |
+----+-------+
| A | 1 |
| B | 2 |
| C | 2 |
| D | 1 |
| E | 1 |
| F | 2 |
| G | 2 |
| H | 2 |
+----+-------+
Where I'm struggling is that a Parent could be a Child to another Parent eg:
Parent B -> Parent -> C -> Child H
These form a Group but there is no direct link between B and H and I am struggling to find a reliable way to identify all associated ID's
This type of logic requires a recursive CTE. The idea is to start at the parents and work your way down the hierarchy:
with cte as (
select row_number() over (order by node) as grp,
n.node as ultimate_parent, n.node as node, 1 as lev
from nodes n
where not exists (select 1 from pc where pc.child = n.node)
union all
select cte.grp, cte.ultimate_parent, pc.child, lev + 1
from cte join
pc
on cte.node = pc.parent
)
update nodes
set grp = cte.grp
from cte
where cte.node = nodes.node;
Here is a db<>fiddle.

SQL query: How to show NULL when there is no retationship between two tables

I have two tables in my DB:
Table A:
ID
P1
P2
Table B:
ID
P3
A_ID which is a foreign key for Table A.ID
Assuming I have the following data in my tables:
+----+----+----+ +----+----+------+
| ID | P1 | P2 | | ID | P3 | A_ID |
+----+----+----+ +----+----+------+
| 1 | aa | aa | | B1 | aa | 1 |
+----+----+----+ +----+----+------+
| 2 | bb | bb |
+----+----+----+
As you can see only the 1st entity of table A has a relationship with an entity of table B, so I want to show (SELECT) something like this and set to 2nd entity of table A NULL values:
+----+----+----+----+
| P1 | P2 | P3 | ID |
+----+----+----+----+
| aa | aa | aa | B1 |
+----+----+----+----+
| bb | bb |null|null|
+----+----+----+----+
Which is the query I need to write in order to achieve that result?
Thanks in advance for your reply.
The relationship is not between individual rows but between tables.
A foreign key is the database way to enforce said relationship.
Having said that - you want a left join query:
SELECT A.P1, A.P2, B.P3, B.ID
FROM A
LEFT JOIN B
ON A.ID = B.A_ID

PostgreSQL can't make Self Join

I have a table:
| acctg_cath_id | parent | description |
| 1 | 20 | Bills |
| 9 | 20 | Invoices |
| 20 | | Expenses |
| 88 | 30 |
| 89 | 30 |
| 30 | |
And I want to create a self join in order to group my items under a parent.
Have tried this, but it doesn't work:
SELECT
accounting.categories.acctg_cath_id,
accounting.categories.parent
FROM accounting.categories a1, accounting.categories a2
WHERE a1.acctg_cath_id=a2.parent
I get error: invalid reference to FROM-clause entry for table "categories"
When I try:
a.accounting.categories.acctg_cath_id
b.accounting.categories.acctg_cath_id
I get error: cross-database references are not implemented: a.accounting.categories.acctg_cath_id
Desired output:
Expenses (Parent 20)
Bills (Child 1)
Invoices (Child 9)
What am I doing wrong here?
It seems you merely want to sort the rows:
select *
from accounting.categorie
order by coalesce(parent, acctg_cath_id), parent nulls first, acctg_cath_id;
Result:
+---------------+--------+-------------+
| acctg_cath_id | parent | description |
+---------------+--------+-------------+
| 20 | | Expenses |
| 1 | 20 | Bills |
| 9 | 20 | Invoices |
| 30 | | |
| 88 | 30 | |
| 89 | 30 | |
+---------------+--------+-------------+
Your syntax is performing a cross join:
FROM accounting.categories a1, accounting.categories a2
Try the following:
SELECT
a2.acctg_cath_id,
a2.parent
FROM accounting.categories a1
JOIN accounting.categories a2 ON (a1.acctg_cath_id = a2.parent)
;
Examine the DBFiddle.
You don't need grouping, only self join:
select
c.acctg_cath_id parentid, c.description parent,
cc.acctg_cath_id childid, cc.description child
from (
select distinct parent
from categories
) p inner join categories c
on p.parent = c.acctg_cath_id
inner join categories cc on cc.parent = p.parent
where p.parent = 20
You can remove the WHERE clause if you want all the parents with all their children.
See the demo.
Results:
> parentid | parent | childid | child
> -------: | :------- | ------: | :-------
> 20 | Expences | 1 | Bills
> 20 | Expences | 9 | Invoices
You don't need a self-join. You don't need aggregation. You just need a group by clause:
SELECT ac.*
FROM accounting.categories ac
ORDER BY COALESCE(ac.parent, ac.acctg_cath_id),
(CASE WHEN ac.parent IS NULL THEN 1 ELSE 2 END),
ac.acctg_cath_id;

How to obtain hierarchical relationships for org units based on positions hierarchy

I have a table containing some HR data including (amongst other details) the position id, the parent position id, and the org unit id.
Something like
pos_id | parent_pos_id | pos_name | org_id | org_name
1 | null | CEO | A | Executive
2 | 1 | Assistant | A | Executive
3 | 1 | IT Director | B | Information Technology
4 | 1 | Finances Director | C | Finances
5 | 3 | Systems Leader | B | Information Technology
6 | 5 | Database Manager | B1 | Database Systems
7 | 5 | Application Manager | B2 | OS and Applications
8 | 4 | Finances Leader | C | Finances
9 | 4 | Financial Assistant | C | Finances
10 | 8 | Payroll Manager | C1 | Payroll
and I need to obtain the information of the parent org unit id for each record, based on the position hierarchical relationships.
So, for the above example, the desired output would be:
org_id | parent_org_id
A | null
B | A
C | A
B1 | B
B2 | B
C1 | C
Is there a query that can be built to obtain this in an SQL Server database?
use self join
DEMO
select a.org_id as org_id,b.org_id as parentorgid
from t1 a
left join t1 b on a.parent_pos_id=b.pos_id
where a.org_id<>b.org_id or b.org_id is null
OUTPUT:
org_id parentorgid
A
B A
C A
B1 B
B2 B
C1 C
You need to write a Recursive CTE for this,The psuedo code is below
with cte as
(
select org_id,parentorg_id,pos_id,parentpos_id from hrtable where parentpos_id is null
UNION ALL
select org_id,parentorg_id,pos_id,parentpos_idfrom hrtable t join cte c on t.parentpso_id=c.pos_id
)
select org_id,parentorg_id from cte c

Find supplier which supplies a product that others don't

I'm trying to write an SQL query which selects the supplier based on the fact that it can supply a product other suppliers cannot.
I have 2 columns:
Supplier and Product
How would I select all the suppliers which supply at least 1 product which other suppliers do not supply?
I currently have:
SELECT incart.product, incart.supplier
FROM incart
WHERE incart.product
HAVING count(incart.supplier)=1
;
Try this:
SELECT
i1.supplier
FROM incart i1
WHERE i1.product NOT IN(SELECT product
FROM incart i2
WHERE i1.supplier <> i2.supplier);
For example, for the following sample data:
| PRODUCT | SUPPLIER |
|---------|----------|
| 1 | a |
| 2 | b |
| 3 | b |
| 2 | c |
| 3 | c |
| 4 | c |
It will select suppliers a and c, because supplier a supplies product 1 which others don't, and supplier c supplies product 4 which others don't.
SQL Fiddle Demo