SQL parent child hierarchy level columns - sql

I need to transform this:
PositionID
ReportsToID
A
B
A
C
B
D
C
E
D
Into this:
PositionID
ReportsToID
Level 1 ID
Level 2 ID
Level 3 ID
Level 4 ID
Level 5 ID
A
A
B
A
A
B
C
B
A
B
C
D
C
A
B
C
D
E
D
A
B
C
D
E
I am a complete SQL novice and no idea how to tackle this... Any help would be greatly appreciated!
Googling for code that has done this already - have not found any

I decided to write a generic solution for unlimited levels. It's possible to walk all the levels using a recursive CTE.
For example:
with recursive
n as (
select position_id, reports_to_id, reports_to_id as rti,
cast(position_id as varchar) as pt
from t
union all
select n.position_id, n.reports_to_id, t.reports_to_id,
t.position_id || ' < ' || n.pt
from n
join t on n.rti = t.position_id
)
select position_id, reports_to_id, pt from n where rti is null
Result:
position_id reports_to_id pt
------------ -------------- -----------------
A null A
B A A < B
C B A < B < C
D C A < B < C < D
E D A < B < C < D < E
See running example at db<>fiddle.
If you need a static solution with a specific number of columns, it can be done with multiple unioned-queries, each one with an increasing number of joins.

Related

Join only the partitions of two tables

SQL Server 2008
Table A looks like:
A_ID v1 v2 v3
---------------------------
1 d e f
1 a b c
1 a b d
2 d a b
2 e f g
3 d e f
3 e f g
3 d a b
and Table B is similar:
B_ID v1 v2 v3
---------------------------
Q a b c
Q b a c
Q a b d
R d e f
R a b c
R d e f
P e f g
P d a b
What I need back from these two tables are the (A_ID, B_ID) pairs, if any, where each row of Table B where B_ID = any one value has one matching row in Table A where A_ID = any one value. In other words, I need to the complete matching set in A for each full set of triples in B--no super sets or subsets. The value of B_ID and A_ID is immaterial.
I thought partitioning would be the way to go, since I already have the column that naturally partitions A and B, and I also thought I could pre-select which paritions where JOINed by ensuring only partitions with matching numbers of rows would be attempting. I haven't been able to do either--partitioning both tables was easy, but I see no way to tell the join to only act on the partitions.
In this example, (2,P) would be returned because all rows in Set P match all rows in Set 2. Result (1, R) would NOT be returned because all rows of Set R are not matched by all rows of Set 1, etc.
Using symetric difference:
SELECT DISTINCT a1.A_ID, b1.B_ID
FROM A a1,B b1
WHERE NOT EXISTS (
(SELECT v1,v2,v3
FROM A WHERE A.A_ID = a1.A_ID
EXCEPT
SELECT v1,v2,v3
FROM B WHERE B.B_ID = b1.B_ID
)
UNION ALL
(
SELECT v1,v2,v3
FROM B WHERE B.B_ID = b1.B_ID
EXCEPT
SELECT v1,v2,v3
FROM A WHERE A.A_ID = a1.A_ID)
);
LiveDemo

Group by and select columns not included in the aggregate

Given I have columns A B C D ….. Z
I want to Group-By on A, B , C Having Count(*) > 1 and then for each of those rows, I want to SELECT the rest of the Columns as well that were not included in the aggregate.
The result would be like
Occurrences A B C D E F G ------- Z
3 e e k q r y e ------- j
3 e e k f t d t ------- y
3 e e k w e q c ------- d
2 f r s w e q c ------- d
2 f r s w e q c ------- d
How can I do that?
You don't want GROUP BY, you want ORDER BY. To get the first column, you can use window functions, which are ANSI standard and supported by most databases:
select t.*
from (select count(*) over (partition by a, b, c) as occurrences,
t.*
from t
order by a, b, c
) t
where occurrences > 1;

SQL - get value from another table if column is null

I'm building matching rules for data reconciliation systems and need your advise on adjusting my sql for it as it currently doesn't return what I need.
There are 2 source tables:
Table X Table Y
--------------------- ----------------------
Exec_ID From To Exec_ID From To
1 A B 1 B C
2 A B 2 B C
3 A B 3 B C
4 A B
5 B C
Matching conditions are:
X.To = Y.From
X.Exec_ID = Y.Exec_ID
if there is A -> B and then B -> C, it should return A -> C in the end.
if there is only A -> B and no further B -> C, it should return A -> B.
So the output should be the following.
From To
---------
A C
A C
A C
A B
SQL I'm using is:
select X.From, Y.To
from x
left outer join y on
x.To = Y.From
and x.Exec_ID = y.Exec_ID
It returns the values like
A C
A C
A C
A Null
So the last record is incorrect as it should be A B. Please help to adjust.
Check for null?
select X.From, [To] = COALESCE(Y.To, X.To)
from x
left outer join y on
x.To = Y.From
and x.Exec_ID = y.Exec_ID

Determine hierarchical relationship, but in reverse

Consider the following table in Oracle
sortOrder thisID levelNo
------------------- ------------------- ---------------------
1 A 0
2 B 1
3 C 1
4 D 2
5 E 3
6 F 3
7 G 1
8 H 0
9 I 1
Which could be seen visually as
A
B
C
D
E
F
G
H
I
How could I determine the child parent relationship, to output the following below? The relationship is based on the sortOrder and levelNo.
thisID parentID
------------------- ---------------------
A A
B A
C A
D C
E D
F D
G A
H H
I H
I am familiar with using queries to determine the level based on a hierarchical parent-child relationship, but haven't figured out a way to do it in reverse.
Please try
SELECT
T.thisID
, CASE T.levelNo
WHEN 0
THEN T.thisID
ELSE (
SELECT thisID FROM Table1
WHERE sortOrder = (
SELECT MAX(sortOrder) FROM Table1
WHERE (levelNo = T.levelNo - 1)
AND sortOrder < T.sortOrder
)
)
END parent
FROM Table1 T
ORDER BY sortOrder;
See it in action: SQL Fiddle.
Please comment if and as further detail / adjustment is required.

SQL Server 2008: concatenate fractions of n-rows together

my table looks like:
column 1 | column 2
--------------------
A L
B M
C N
D O
E P
F Q
G R
H S
I T
J U
K V
Now I want to "concatenate" fractions of n-rows (n is variable) together.
For example:
-) if n = 4, the output should be:
column 1 | column 2 | column 1 | column 2 | column 1 | column 2
A L E P I T
B M F Q J U
C N G R K V
D O H S
-) if n = 10, the output should be:
column 1 | column 2 | column 1 | column 2
A L K V
B M
C N
D O
E P
F Q
G R
H S
I T
J U
I thought about using a temp table and a loop. After every iteration, I select fractions of n-rows and concatenate them together (with union). However, I think this solution could be a little slow for large datasets.
Maybe someone of you knows a better approach?
I would really appreciate if someone could help me with this.
Kind Regards
Bernhard
this is not complete
pivot is left,i was thinking of doing something like this,
Declare #n int=4
Declare #j int
Declare #k int
Select #j=count(*) from #t
if(#j%#n=0)
set #k= (#j/#n)
else
set #k= (#j/#n)+1
--select #k
;with CTE as
(
select *,ntile(#k)over(order by column1)rn from #t
)
select * from cte