Oracle SQ Identify Siblings via siblings

情到浓时终转凉″ 提交于 2021-01-29 09:08:33

问题


I have linked together groups of records which are related via a shared parent. Unfortunately there are some quite complicated family groups, and it's become clear that just using a shared parental relationship isn't enough - I also want to take into account sibling relationships.

To be clear - this is actual family groups, which are currently identified if their is a shared mother or father relationship, but in some cases a child may not share parents with another child who is still linked to them via a sibling.

So in the above example, Lou has no shared parental relationship with Stacey, but Stacey is the sister of Nate who is the brother of Deb who is the sister of Lou, which links them together.

For arguments sake let's say we have some SQL like this:

SELECT A.ID, A.SIBS FROM A

Which produces a dataset like this:

ID  SIBS
A   B
A   C
B   A
C   A
C   D
D   C

I would like to produce a table from the above dataset which takes into account siblings of siblings - for example sibling C is related to sibling D and Sibling A, but is related to sibling B via sibling A. The resulting table would look like this:

ID  SIBS
A   B
A   C
A   D
B   C
B   D
B   A
C   A
C   D
C   B
D   C
D   A
D   B

Any advice would be appreciated.


回答1:


Its unclear whether the relationships are reflexive (i.e. if B is a "sibling" of A then A is a "sibling" of B) as you have some duplicate rows with the reversed relationships in your data and some where this property is not evident.

Assuming that your relationships are not reflexive then:

SQL Fiddle

Oracle 11g R2 Schema Setup:

CREATE TABLE A ( ID, SIBS ) AS
SELECT 'A', 'B' FROM DUAL UNION ALL
SELECT 'A', 'C' FROM DUAL UNION ALL
SELECT 'B', 'A' FROM DUAL UNION ALL
SELECT 'C', 'A' FROM DUAL UNION ALL
SELECT 'C', 'D' FROM DUAL UNION ALL
SELECT 'D', 'C' FROM DUAL UNION ALL
SELECT 'E', 'F' FROM DUAL UNION ALL
SELECT 'F', 'G' FROM DUAL UNION ALL
SELECT 'G', 'H' FROM DUAL;

Query 1:

SELECT DISTINCT
       CONNECT_BY_ROOT( ID ) AS ID,
       SIBS
FROM   A
WHERE  CONNECT_BY_ROOT( ID ) <> SIBS
CONNECT BY NOCYCLE
       PRIOR SIBS = ID
ORDER BY ID, SIBS

Results:

| ID | SIBS |
|----|------|
|  A |    B |
|  A |    C |
|  A |    D |
|  B |    A |
|  B |    C |
|  B |    D |
|  C |    A |
|  C |    B |
|  C |    D |
|  D |    A |
|  D |    B |
|  D |    C |
|  E |    F |
|  E |    G |
|  E |    H |
|  F |    G |
|  F |    H |
|  G |    H |

Query 2: If they are reflexive then you can use UNION [ALL] to duplicate the table with the relationships in the reverse direction and then use the previous technique:

SELECT DISTINCT
       CONNECT_BY_ROOT( ID ) AS ID,
       SIBS
FROM   (
  SELECT ID, SIBS FROM A
  UNION
  SELECT SIBS, ID FROM A
)
WHERE  CONNECT_BY_ROOT( ID ) <> SIBS
CONNECT BY NOCYCLE
       PRIOR SIBS = ID
ORDER BY ID, SIBS

Results:

| ID | SIBS |
|----|------|
|  A |    B |
|  A |    C |
|  A |    D |
|  B |    A |
|  B |    C |
|  B |    D |
|  C |    A |
|  C |    B |
|  C |    D |
|  D |    A |
|  D |    B |
|  D |    C |
|  E |    F |
|  E |    G |
|  E |    H |
|  F |    E |
|  F |    G |
|  F |    H |
|  G |    E |
|  G |    F |
|  G |    H |
|  H |    E |
|  H |    F |
|  H |    G |



回答2:


As an alternative to a hierarchical query, you coudl also use recursive subquery factoring:

with r (pno, sibs) as (
  select a.id, a.sibs
  from a
  union all
  select r.pno, a.sibs
  from r
  join a on a.id = r.sibs
)
cycle pno, sibs set is_cycle to 1 default 0
select distinct pno, sibs
from r
where pno != sibs
order by pno, sibs;

PNO SIBS
--- ----
A   B   
A   C   
A   D   
B   A   
B   C   
B   D   
C   A   
C   B   
C   D   
D   A   
D   B   
D   C   

The anchor member gets the raw data from your table. The recursive member joins each row found so far back to your main table, keeping the original pno (as the equivalent to connect_by_root(id)).

The hierarchical query is likely to perform better, I think, but it depends a bit on your data, so you could try both approaches.



来源:https://stackoverflow.com/questions/53616010/oracle-sq-identify-siblings-via-siblings

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!