从 parent/child 条记录中获取 Oracle SQL 顶级父记录
Getting Oracle SQL top level parent record from a number of parent/child records
我正在尝试创建一个 Oracle SQL 语句以从不同级别的多个父子记录中获取顶级根级父记录。 table 结构如下。下面的顶级根父级是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;
得出答案。 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
这个有效,但由于记录 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;
将PRIOR
关键字放在PARENT_MEMBERSHIP_ID
的CONNECT BY
子句中,导致树向根遍历,并使"root"个节点离开。
如果您要寻找共同祖先,则需要采用不同的方法:
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;
我正在尝试创建一个 Oracle SQL 语句以从不同级别的多个父子记录中获取顶级根级父记录。 table 结构如下。下面的顶级根父级是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;
得出答案。 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
这个有效,但由于记录 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;
将PRIOR
关键字放在PARENT_MEMBERSHIP_ID
的CONNECT BY
子句中,导致树向根遍历,并使"root"个节点离开。
如果您要寻找共同祖先,则需要采用不同的方法:
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;