Oracle SQL 通过兄弟姐妹识别兄弟姐妹

Oracle SQ Identify Siblings via siblings

我已将通过共享 parent 关联的记录组链接在一起。不幸的是,有一些相当复杂的家庭群体,很明显仅使用共享 parental 关系是不够的 - 我还想考虑兄弟姐妹关系。

需要说明的是 - 这是实际的家庭群体,如果他们是共同的母亲或父亲关系,则目前被识别出来,但在某些情况下,child 可能不会与另一个人共享 parent child 谁仍然通过兄弟姐妹与他们联系。

所以在上面的例子中,Lou 与 Stacey 没有共同的 parental 关系,但 Stacey 是 Nate 的妹妹,Nate 是 Deb 的兄弟,Deb 是 Lou 的妹妹,这将他们联系在一起。

为了争论起见,假设我们有一些 SQL 这样的:

SELECT A.ID, A.SIBS FROM A

产生这样的数据集:

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

我想从上面的数据集中生成一个 table,它考虑了兄弟姐妹的兄弟姐妹 - 例如兄弟姐妹 C 与兄弟姐妹 D 和兄弟姐妹 A 相关,但通过兄弟姐妹 A 与兄弟姐妹 B 相关. 结果 table 看起来像这样:

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

如有任何建议,我们将不胜感激。

不清楚这些关系是否自反(即,如果 BA 的 "sibling",则 A 是 [=15 的 "sibling" =]) 因为您的数据中有一些具有相反关系的重复行,而有些 属性 不明显。

假设你的关系不是自反的:

SQL Fiddle

Oracle 11g R2 架构设置:

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;

查询 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 |

查询 2:如果它们是自反的,那么您可以使用 UNION [ALL] 以反向关系复制 table,然后使用以前的技术:

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 |

作为分层查询的替代方法,您还可以使用 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   

主播成员从您的table获取原始数据。递归成员将到目前为止找到的每一行连接到您的主table,保持原始pno(相当于connect_by_root(id))。

我认为分层查询可能会执行得更好,但这在一定程度上取决于您的数据,因此您可以尝试这两种方法。