【问题标题】:Oracle SQ Identify Siblings via siblingsOracle SQL 通过兄弟姐妹识别兄弟姐妹
【发布时间】:2019-05-06 01:27:39
【问题描述】:

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

需要说明的是 - 这是实际的家庭组,如果他们是共同的母亲或父亲关系,则目前已确定,但在某些情况下,孩子可能不会与仍然通过兄弟姐妹与他们联系的另一个孩子分享父母。

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

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

SELECT A.ID, A.SIBS FROM A

生成这样的数据集:

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

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

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

任何建议将不胜感激。

【问题讨论】:

  • 请将您的示例作为格式化文本插入。
  • 你误用了兄弟这个词。兄弟姐妹是可传递的:如果 A 是 B 的兄弟姐妹,B 是 C 的兄弟姐妹,则 A 是 C 的兄弟姐妹。找到另一个更能描述这种关系的词。
  • @Tony94 - 抱歉,我总是遇到这个问题。我尝试从 excel 粘贴到帖子中,它会自动将其作为图片进行。
  • @RedFilter - 实际上,这是在谈论真正的家庭兄弟姐妹,但我明白你的意思。我不知道如何描述它们——有些共享父母,有些只是共享兄弟姐妹。

标签: sql oracle recursion hierarchy


【解决方案1】:

不清楚这些关系是否是自反的(即如果BA 的“兄弟”,那么AB 的“兄弟”),因为您有一些重复的行,其中的反向关系您的数据和一些此属性不明显的地方。

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

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] 复制具有反向关系的表,然后使用前面的技术:

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 |

【讨论】:

  • 感谢您的回复,您的假设是正确的,即他们不是自反的,数据基于实际的家庭组,其中至少有一个共同的父母,但在某些情况下您可能有孩子他们没有共同的父母,但他们确实有一个兄弟姐妹!解决方案 A 有效。
【解决方案2】:

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

锚成员从您的表中获取原始数据。递归成员将到目前为止找到的每一行连接回您的主表,保留原始的 pno(等同于 connect_by_root(id))。

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

【讨论】:

  • 谢谢你,正如你所说@MT0 提供的答案工作得更快,所以我将其标记为答案,但是有一个替代方案很有帮助(再次,我知道这很难当您看不到数据集时)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-29
  • 1970-01-01
  • 1970-01-01
  • 2015-03-06
  • 1970-01-01
相关资源
最近更新 更多