在 Oracle 中使用先验垂直连接而不是水平连接获取路径层次结构?
Get path hierarhy using connect by prior vertical instead of horizontal in Oracle?
您好,我有一个使用 connect by prior
的 SQL 语句。我想通过特定的 where
标准获取路径。以下 SQL 工作正常,但我不想只获得符合条件的一行,我还想获得每个父记录(垂直向上层次结构)。
SELECT SUBSTR(SYS_CONNECT_BY_PATH(R.CALCULATION_PLAN_CODE, '.'),4) CODE_PATH,
SUBSTR(SYS_CONNECT_BY_PATH(R.CALCULATION_PLAN_NAME, ' > '),29) NAME_PATH,
R.CALCULATION_PLAN_CODE,
R.CALCULATION_PLAN_NAME
FROM PRM.MOVABLE_CALCULATION_PLAN R
WHERE R.RELATED_YEAR = :relatedYear
AND R.CALCULATION_PLAN_PARENT_OID != 0
AND REGEXP_LIKE (R.CALCULATION_PLAN_NAME,'ROL')
AND CONNECT_BY_ISLEAF = 1
START WITH R.OID =
(SELECT R1.OID
FROM PRM.MOVABLE_CALCULATION_PLAN R1
WHERE (R1.CALCULATION_PLAN_PARENT_OID IS NULL OR R1.CALCULATION_PLAN_PARENT_OID = 0) AND R1.RELATED_YEAR=:relatedYear) CONNECT_BY_PRIOR R.OID = R.CALCULATION_PLAN_PARENT_OID;
我不想要这样的输出:
我想要这样:
150 İLK MADDE VE MALZEMELER
150.1 İLK MADDE VE MALZEMELER > KIRTASİYE MALZEMELERİ GRUBU
150.1.1 İLK MADDE VE MALZEMELER > KIRTASİYE MALZEMELERİ GRUBU > ROL <-----
150 İLK MADDE VE MALZEMELER
150.1 İLK MADDE VE MALZEMELER > KIRTASİYE MALZEMELERİ GRUBU
150.1.1 İLK MADDE VE MALZEMELER > KIRTASİYE MALZEMELERİ GRUBU > YAZI ARAÇLARI
150.1.1.1 İLK MADDE VE MALZEMELER > KIRTASİYE MALZEMELERİ GRUBU > YAZI ARAÇLARI > ROLLER KALEM <-----
如何实现?
提前致谢
一个解决方案将需要多次解决您的 table,因为您想要的输出可能有重复:部分路径(例如“150.1”)可能导致两个不同的兴趣叶,因此它将出现两次(或更多)。
请注意,您不需要在 start with
子句中重复 where
条件。无论如何都会应用它们,也适用于起始记录。
这里是查询:
SELECT NODE.CODE_PATH, NODE.NAME_PATH FROM
(
SELECT OID,
SYS_CONNECT_BY_PATH(R.OID, ',') OID_PATH
FROM MOVABLE_CALCULATION_PLAN R
WHERE REGEXP_LIKE (R.CALCULATION_PLAN_NAME,'ROL')
AND CONNECT_BY_ISLEAF = 1
AND R.RELATED_YEAR = :relatedYear
START WITH NVL(CALCULATION_PLAN_PARENT_OID, 0) = 0
CONNECT BY PRIOR R.OID = R.CALCULATION_PLAN_PARENT_OID
) LEAF
INNER JOIN
(
SELECT SUBSTR(SYS_CONNECT_BY_PATH(R.CALCULATION_PLAN_CODE, '.'),2) CODE_PATH,
SUBSTR(SYS_CONNECT_BY_PATH(R.CALCULATION_PLAN_NAME, ' > '),4) NAME_PATH,
OID,
SYS_CONNECT_BY_PATH(R.OID, ',') OID_PATH
FROM MOVABLE_CALCULATION_PLAN R
START WITH NVL(CALCULATION_PLAN_PARENT_OID, 0) = 0
CONNECT BY PRIOR R.OID = R.CALCULATION_PLAN_PARENT_OID
) NODE
ON NODE.OID = LEAF.OID
OR LEAF.OID_PATH LIKE '%,' || NODE.OID || ',%'
结果:
CODE_PATH NAME_PATH
---------- ------------------------------------------------------------
150 İLK MADDE VE MALZEMELER
150.1 İLK MADDE VE MALZEMELER > KIRTASİYE MALZEMELERİ GRUBU
150.1.1 İLK MADDE VE MALZEMELER > KIRTASİYE MALZEMELERİ GRUBU > ROL
150 İLK MADDE VE MALZEMELER
150.1 İLK MADDE VE MALZEMELER > KIRTASİYE MALZEMELERİ GRUBU
150.1.1 İLK MADDE VE MALZEMELER > KIRTASİYE MALZEMELERİ GRUBU > YAZI ARAÇLARI
150.1.1.1 İLK MADDE VE MALZEMELER > KIRTASİYE MALZEMELERİ GRUBU > YAZI ARAÇLARI > ROL
还有一个fiddle.
想法是,在第一个子 select 中,您 select 叶子,具有您提供的 where
条件。然后你做另一个 sub-select that selects all nodes with their paths,没有任何过滤。最后,您将这些节点匹配为第一个过滤叶节点的下降线。
你想要的东西比较复杂,但它是可以解决的。不过,您需要构建多棵树:对于第一个查询,您通过 反向连接 ,从叶单元开始,构建直到根节点的分支,并跟踪leaf 使用 connect_by_root
函数构建分支。然后,在第二个查询中,您 connect by
基于第一个查询的结果,这次以正确的顺序进行,但另外匹配您之前跟踪的叶 ID。
with Q as
(
SELECT CONNECT_BY_ROOT(R.OID) leafid, R.*
FROM MOVABLE_CALCULATION_PLAN R
CONNECT BY R.OID = PRIOR R.CALCULATION_PLAN_PARENT_OID
START WITH R.RELATED_YEAR = 2015
AND REGEXP_LIKE (R.CALCULATION_PLAN_NAME,'ROL')
AND R.CALCULATION_PLAN_PARENT_OID != 0
/*Following condition is replacement for CONNECT_BY_ISLEAF = 1,
Since you're connecting in reverse you can't use it*/
AND not exists
(select 'x' from MOVABLE_CALCULATION_PLAN R2
where R2.CALCULATION_PLAN_PARENT_OID = R.OID)
)
select SUBSTR(SYS_CONNECT_BY_PATH(Q.CALCULATION_PLAN_CODE, '.'),2) CODE_PATH,
SUBSTR(SYS_CONNECT_BY_PATH(Q.CALCULATION_PLAN_NAME, ' > '),4) NAME_PATH
from Q
CONNECT BY PRIOR Q.OID = Q.CALCULATION_PLAN_PARENT_OID
and prior Q.leafid = leafid
START WITH NVL(CALCULATION_PLAN_PARENT_OID, 0) = 0
与按查询连接一样,性能可能是个问题,但从我在类似 table 结构上看到的情况来看,它仍然相当快。另见 http://sqlfiddle.com/#!4/dd5b68/6
P.S。以后一定要给我们提供样本数据和体面的描述你的情况,不要让我们破译你的问题,自己想出样本。
您好,我有一个使用 connect by prior
的 SQL 语句。我想通过特定的 where
标准获取路径。以下 SQL 工作正常,但我不想只获得符合条件的一行,我还想获得每个父记录(垂直向上层次结构)。
SELECT SUBSTR(SYS_CONNECT_BY_PATH(R.CALCULATION_PLAN_CODE, '.'),4) CODE_PATH,
SUBSTR(SYS_CONNECT_BY_PATH(R.CALCULATION_PLAN_NAME, ' > '),29) NAME_PATH,
R.CALCULATION_PLAN_CODE,
R.CALCULATION_PLAN_NAME
FROM PRM.MOVABLE_CALCULATION_PLAN R
WHERE R.RELATED_YEAR = :relatedYear
AND R.CALCULATION_PLAN_PARENT_OID != 0
AND REGEXP_LIKE (R.CALCULATION_PLAN_NAME,'ROL')
AND CONNECT_BY_ISLEAF = 1
START WITH R.OID =
(SELECT R1.OID
FROM PRM.MOVABLE_CALCULATION_PLAN R1
WHERE (R1.CALCULATION_PLAN_PARENT_OID IS NULL OR R1.CALCULATION_PLAN_PARENT_OID = 0) AND R1.RELATED_YEAR=:relatedYear) CONNECT_BY_PRIOR R.OID = R.CALCULATION_PLAN_PARENT_OID;
我不想要这样的输出:
150 İLK MADDE VE MALZEMELER
150.1 İLK MADDE VE MALZEMELER > KIRTASİYE MALZEMELERİ GRUBU
150.1.1 İLK MADDE VE MALZEMELER > KIRTASİYE MALZEMELERİ GRUBU > ROL <-----
150 İLK MADDE VE MALZEMELER
150.1 İLK MADDE VE MALZEMELER > KIRTASİYE MALZEMELERİ GRUBU
150.1.1 İLK MADDE VE MALZEMELER > KIRTASİYE MALZEMELERİ GRUBU > YAZI ARAÇLARI
150.1.1.1 İLK MADDE VE MALZEMELER > KIRTASİYE MALZEMELERİ GRUBU > YAZI ARAÇLARI > ROLLER KALEM <-----
如何实现?
提前致谢
一个解决方案将需要多次解决您的 table,因为您想要的输出可能有重复:部分路径(例如“150.1”)可能导致两个不同的兴趣叶,因此它将出现两次(或更多)。
请注意,您不需要在 start with
子句中重复 where
条件。无论如何都会应用它们,也适用于起始记录。
这里是查询:
SELECT NODE.CODE_PATH, NODE.NAME_PATH FROM
(
SELECT OID,
SYS_CONNECT_BY_PATH(R.OID, ',') OID_PATH
FROM MOVABLE_CALCULATION_PLAN R
WHERE REGEXP_LIKE (R.CALCULATION_PLAN_NAME,'ROL')
AND CONNECT_BY_ISLEAF = 1
AND R.RELATED_YEAR = :relatedYear
START WITH NVL(CALCULATION_PLAN_PARENT_OID, 0) = 0
CONNECT BY PRIOR R.OID = R.CALCULATION_PLAN_PARENT_OID
) LEAF
INNER JOIN
(
SELECT SUBSTR(SYS_CONNECT_BY_PATH(R.CALCULATION_PLAN_CODE, '.'),2) CODE_PATH,
SUBSTR(SYS_CONNECT_BY_PATH(R.CALCULATION_PLAN_NAME, ' > '),4) NAME_PATH,
OID,
SYS_CONNECT_BY_PATH(R.OID, ',') OID_PATH
FROM MOVABLE_CALCULATION_PLAN R
START WITH NVL(CALCULATION_PLAN_PARENT_OID, 0) = 0
CONNECT BY PRIOR R.OID = R.CALCULATION_PLAN_PARENT_OID
) NODE
ON NODE.OID = LEAF.OID
OR LEAF.OID_PATH LIKE '%,' || NODE.OID || ',%'
结果:
CODE_PATH NAME_PATH
---------- ------------------------------------------------------------
150 İLK MADDE VE MALZEMELER
150.1 İLK MADDE VE MALZEMELER > KIRTASİYE MALZEMELERİ GRUBU
150.1.1 İLK MADDE VE MALZEMELER > KIRTASİYE MALZEMELERİ GRUBU > ROL
150 İLK MADDE VE MALZEMELER
150.1 İLK MADDE VE MALZEMELER > KIRTASİYE MALZEMELERİ GRUBU
150.1.1 İLK MADDE VE MALZEMELER > KIRTASİYE MALZEMELERİ GRUBU > YAZI ARAÇLARI
150.1.1.1 İLK MADDE VE MALZEMELER > KIRTASİYE MALZEMELERİ GRUBU > YAZI ARAÇLARI > ROL
还有一个fiddle.
想法是,在第一个子 select 中,您 select 叶子,具有您提供的 where
条件。然后你做另一个 sub-select that selects all nodes with their paths,没有任何过滤。最后,您将这些节点匹配为第一个过滤叶节点的下降线。
你想要的东西比较复杂,但它是可以解决的。不过,您需要构建多棵树:对于第一个查询,您通过 反向连接 ,从叶单元开始,构建直到根节点的分支,并跟踪leaf 使用 connect_by_root
函数构建分支。然后,在第二个查询中,您 connect by
基于第一个查询的结果,这次以正确的顺序进行,但另外匹配您之前跟踪的叶 ID。
with Q as
(
SELECT CONNECT_BY_ROOT(R.OID) leafid, R.*
FROM MOVABLE_CALCULATION_PLAN R
CONNECT BY R.OID = PRIOR R.CALCULATION_PLAN_PARENT_OID
START WITH R.RELATED_YEAR = 2015
AND REGEXP_LIKE (R.CALCULATION_PLAN_NAME,'ROL')
AND R.CALCULATION_PLAN_PARENT_OID != 0
/*Following condition is replacement for CONNECT_BY_ISLEAF = 1,
Since you're connecting in reverse you can't use it*/
AND not exists
(select 'x' from MOVABLE_CALCULATION_PLAN R2
where R2.CALCULATION_PLAN_PARENT_OID = R.OID)
)
select SUBSTR(SYS_CONNECT_BY_PATH(Q.CALCULATION_PLAN_CODE, '.'),2) CODE_PATH,
SUBSTR(SYS_CONNECT_BY_PATH(Q.CALCULATION_PLAN_NAME, ' > '),4) NAME_PATH
from Q
CONNECT BY PRIOR Q.OID = Q.CALCULATION_PLAN_PARENT_OID
and prior Q.leafid = leafid
START WITH NVL(CALCULATION_PLAN_PARENT_OID, 0) = 0
与按查询连接一样,性能可能是个问题,但从我在类似 table 结构上看到的情况来看,它仍然相当快。另见 http://sqlfiddle.com/#!4/dd5b68/6
P.S。以后一定要给我们提供样本数据和体面的描述你的情况,不要让我们破译你的问题,自己想出样本。