【问题标题】:Getting Oracle SQL top level parent record from a number of parent/child records从多个父/子记录中获取 Oracle SQL 顶级父记录
【发布时间】:2016-12-13 15:57:57
【问题描述】:

我正在尝试创建一个 Oracle SQL 语句,以从不同级别的多个父子记录中获取顶级根级别父记录。表结构如下。下面的顶级根父母是 parent_membership_id 53887,这个父母记录有许多孩子,他们也是其他孩子的父母。我想要的是一个查询,如果我查询说 200326 的成员,查询会带回根成员 53887,或者如果我查询 200322,我会得到根成员 53887。我想你知道我想要做什么。提前致谢。

 CREATE TABLE MEMBERSHIP_LINK
 ( MEMBERSHIP_LINK_ID        NUMBER(10)          NOT NULL,
   CHILD_MEMBERSHIP_ID       NUMBER(10)          NOT NULL,
   PARENT_MEMBERSHIP_ID      NUMBER(10)          NOT NULL);

Insert into MEMBERSHIP_LINK
   (MEMBERSHIP_LINK_ID, CHILD_MEMBERSHIP_ID, PARENT_MEMBERSHIP_ID)
 Values
   (35, 53890, 53887);
Insert into MEMBERSHIP_LINK
   (MEMBERSHIP_LINK_ID, CHILD_MEMBERSHIP_ID, PARENT_MEMBERSHIP_ID)
 Values
   (24475, 200322, 53887);
Insert into MEMBERSHIP_LINK
   (MEMBERSHIP_LINK_ID, CHILD_MEMBERSHIP_ID, PARENT_MEMBERSHIP_ID)
 Values
   (24476, 200322, 53887);
Insert into MEMBERSHIP_LINK
   (MEMBERSHIP_LINK_ID, CHILD_MEMBERSHIP_ID, PARENT_MEMBERSHIP_ID)
 Values
   (34, 53889, 53888);
Insert into MEMBERSHIP_LINK
   (MEMBERSHIP_LINK_ID, CHILD_MEMBERSHIP_ID, PARENT_MEMBERSHIP_ID)
 Values
   (5941, 112177, 53889);
Insert into MEMBERSHIP_LINK
   (MEMBERSHIP_LINK_ID, CHILD_MEMBERSHIP_ID, PARENT_MEMBERSHIP_ID)
 Values
   (33, 53888, 53890);
Insert into MEMBERSHIP_LINK
   (MEMBERSHIP_LINK_ID, CHILD_MEMBERSHIP_ID, PARENT_MEMBERSHIP_ID)
 Values
   (24477, 200323, 200322);
Insert into MEMBERSHIP_LINK
   (MEMBERSHIP_LINK_ID, CHILD_MEMBERSHIP_ID, PARENT_MEMBERSHIP_ID)
 Values
   (24478, 200323, 200322);
Insert into MEMBERSHIP_LINK
   (MEMBERSHIP_LINK_ID, CHILD_MEMBERSHIP_ID, PARENT_MEMBERSHIP_ID)
 Values
   (24479, 200325, 200323);
Insert into MEMBERSHIP_LINK
   (MEMBERSHIP_LINK_ID, CHILD_MEMBERSHIP_ID, PARENT_MEMBERSHIP_ID)
 Values
   (24480, 200326, 200323);
COMMIT;

【问题讨论】:

  • MEMBERSHIP_LINK_IDs 24477 和 24478 代表同一个关系是不是故意的?
  • 这只是一个与父母或孩子无关的唯一键
  • MEMBERSHIP_LINK_IDs 24477 和 24478 都具有相同的 CHILD_MEMBERSHIP_IDPARENT_MEMBERSHIP_IDs(分别为 200323 和 200322),因此 MEMBERSHIP_LINK_IDs 24477 和 24478 似乎代表相同的关系。

标签: sql oracle11g hierarchical-data recursive-query connect-by


【解决方案1】:

这个可行,但由于记录 24477 和 24478 定义了相同的关系,因此它需要不同的运算符。

 SELECT DISTINCT ML.PARENT_MEMBERSHIP_ID
   FROM MEMBERSHIP_LINK ml
  WHERE CONNECT_BY_ISLEAF = 1  -- Limit to the "Root" element(s)
  START WITH ML.CHILD_MEMBERSHIP_ID = :decendent_id
CONNECT BY ML.CHILD_MEMBERSHIP_ID = prior ML.PARENT_MEMBERSHIP_ID;

PARENT_MEMBERSHIP_ID 上的CONNECT BY 子句中放置PRIOR 关键字会导致树向根方向遍历,并使“根”节点离开。

如果您要寻找共同的祖先,则需要一种不同的方法:

WITH ancestry AS
  ( SELECT DISTINCT CONNECT_BY_ROOT CHILD_MEMBERSHIP_ID child_id
         , ML.PARENT_MEMBERSHIP_ID ancestor_id
         , level generation_gap
         , CONNECT_BY_ISLEAF
      FROM MEMBERSHIP_LINK ml
     START WITH ML.CHILD_MEMBERSHIP_ID in (:Descendent_ID1,:Descendent_ID2)
   CONNECT BY ML.CHILD_MEMBERSHIP_ID = prior ML.PARENT_MEMBERSHIP_ID
  )
 SELECT ancestor_id
   FROM ancestry
  WHERE child_id = :Descendent_ID1
INTERSECT
 SELECT ancestor_id
   FROM ancestry
  WHERE child_id = :Descendent_ID2;

由此您可以确定最近(最小)的共享祖先、最老的共享祖先和共同血统:

WITH ancestry AS (
   SELECT DISTINCT CONNECT_BY_ROOT CHILD_MEMBERSHIP_ID child_id
        , ML.PARENT_MEMBERSHIP_ID ancestor_id
        , level generation_gap
        , CONNECT_BY_ISLEAF
     FROM MEMBERSHIP_LINK ml
    START WITH ML.CHILD_MEMBERSHIP_ID in (:Descendent_ID1,:Descendent_ID2)
  CONNECT BY ML.CHILD_MEMBERSHIP_ID = prior ML.PARENT_MEMBERSHIP_ID
  ), common AS (
   SELECT ancestor_id
     FROM ancestry
    WHERE child_id = :Descendent_ID1
INTERSECT
   SELECT ancestor_id
     FROM ancestry
    WHERE child_id = :Descendent_ID2
  )
 SELECT MIN( a.ANCESTOR_ID ) keep( dense_rank FIRST ORDER BY a.GENERATION_GAP ) Youngest_Ancestor
      , LISTAGG(a.ANCESTOR_ID, '->') within group (order by a.GENERATION_GAP) common_lineage
      , MIN( a.ANCESTOR_ID ) keep( dense_rank FIRST ORDER BY a.GENERATION_GAP desc ) Oldest_Ancestor
   FROM ancestry a
   JOIN common c
     ON a.ancestor_id = c.ancestor_id
  WHERE a.child_id    = :Descendent_ID1;

【讨论】:

    【解决方案2】:

    想出了答案。 SQL如下。

    SELECT DISTINCT meli.parent_membership_id
           FROM   MEMBERSHIP_LINK meli
           WHERE  LEVEL = ( SELECT max(level)
                 FROM    MEMBERSHIP_LINK meli_in
                 START WITH meli_in.child_membership_id = :membership_id
                 CONNECT BY meli_in.child_membership_id = PRIOR meli_in.parent_membership_id )
           START WITH meli.child_membership_id = :membership_id
           CONNECT BY meli.child_membership_id = prior meli.parent_membership_id
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-02-21
      • 2012-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多