Sql 检索表中的层次结构
我一直在使用一个查询来检索数据库中文件的层次结构。下面是该表的示例:Sql 检索表中的层次结构,sql,oracle,Sql,Oracle,我一直在使用一个查询来检索数据库中文件的层次结构。下面是该表的示例: _Name_ _HierarchyPath_ Parallel EEPROM 163796003/1761551443/413793741/1362244494/110367462/3988861187/3597067685/4208992221 Parallel Flash 163796003/1761551443/413793741/13
_Name_ _HierarchyPath_
Parallel EEPROM 163796003/1761551443/413793741/1362244494/110367462/3988861187/3597067685/4208992221
Parallel Flash 163796003/1761551443/413793741/1362244494/110367462/3988861187/3597067685/1995340606
Parallel I-F 163796003/1761551443/413793741/1362244494/110367462/391521622/2389021280/3222611234
Parallel I-F 163796003/1761551443/413793741/1362244494/110367462/391521622/4124681422/3222611234
Parallel, In-line 163796003/1761551443/413793741/977119157/977119157/1065183491/4216548299/92850509/1330595286
Serial\Parallel I-F 163796003/1761551443/413793741/1362244494/110367462/391521622/4124681422/92930422
所以基本上,我计算出HierarchyPath
中的最后一个数字是数据库中对象的HierarchyID
。我需要的是一种检索对象完整路径的方法(意味着/
之间的每个数字都等于一个对象)。我成功地找到了某物的整个路径,但有多行。如果可能的话,我想把它排成一行
以下是我当前的查询和结果(对于第一个表中的第二个并行I-F
):
其结果是:
Part 163796003/1761551443/413793741
Electronic 163796003/1761551443/413793741/1362244494
Integrated Circuits 163796003/1761551443/413793741/1362244494/110367462
Data Acquisition 163796003/1761551443/413793741/1362244494/110367462/391521622
Parallel I-F 163796003/1761551443/413793741/1362244494/110367462/391521622/2389021280/3222611234
ADC 163796003/1761551443/413793741/1362244494/110367462/391521622/4124681422
Parallel I-F 163796003/1761551443/413793741/1362244494/110367462/391521622/4124681422/3222611234
Data Acquisition 163796003/1761551443/413793741/1362244494/40756919/3258224989/2899710639/391521622
我如何获得类似于零件/电子/集成电路/数据采集/ADC/Parallel-I-F
我目前正在尝试在同一个表上使用左联接,但没有成功。我也读过关于使用CTE的书,但我从未成功地使用过。我是SQL开发人员,但不介意其他环境答案 你想要的似乎是可能的。但我无法从您(在这方面很差)的描述中完全理解您的表的结构。因此,我将制定自己的计划来演示如何做到这一点。你必须自己在你的模式中翻译它 既然你提到了SQL开发者,我猜你在使用Oracle。您还没有标记正在使用的DBMS 表
OBJECT
存储具有名称和ID的对象
CREATE TABLE OBJECT
(ID NUMBER(38),
NAME VARCHAR2(8));
表层次结构
以对象ID的字符串形式存储对象的路径,以'/'
和ID分隔
CREATE TABLE HIERARCHY
(ID NUMBER(38),
PATH VARCHAR2(8));
现在我们需要的第一件事是一个数字表,它包含从1到层次结构中路径中对象的最大值的整数。我们可以使用递归CTE来实现这一点
WITH CTE(I)
AS
(
SELECT 1 I
FROM DUAL
UNION ALL
SELECT CTE.I + 1 I
FROM CTE
WHERE CTE.I <= (SELECT MAX(REGEXP_COUNT(HIERARCHY.PATH, '/')) + 1
FROM HIERARCHY)
)
我们再次可以使用REGEXP_COUNT(HIERARCHY.PATH,“/”)+1
将路径中对象数量较少或相等的所有数字连接起来
CTE.I
现在将对层次结构中的行进行编号
,对于路径中的每个对象,有一个整数,从1到路径中的整数总数(或NULL
,如果路径为NULL
)
我们可以在连接的结果中使用CTE.I
从路径中提取对象ID,即路径中的第CTE.I
-th位置。为此,我们可以使用REGEXP\u SUBSTR()
:
该模式匹配字符串开头或'/'
之后不是'/'
的所有字符。第四个参数,CTE.I
,告诉函数返回第次匹配。这就是我们获取路径中各个位置的相关对象ID的方式。不幸的是,在返回的匹配项的开头可能有不必要的'/'
,因此我们将其包装在REGEXP\u REPLACE()
中以删除它们
REGEXP_REPLACE(REGEXP_SUBSTR(HIERARCHY.PATH, '(^|/)[^/]+', 1, CTE.I), '^/')
有了它,我们现在可以左键连接对象
。我们只是在_NUMBER()
中加入了一个额外的
加入OBJECT
后,我们就快完成了。现在,我们根据输出中所需的HIERARCHY
列对HIERARCHY
进行分组,例如HIERARCHY.ID
和HIERARCHY.PATH
,并再次使用LISTAGG()
将对象名称连接到由'/'分隔的路径
LISTAGG(OBJECT.NAME, '/') WITHIN GROUP (ORDER BY CTE.I) OBJECT_PATH
CTE.I的顺序确保每个对象名称都位于路径中的正确位置
我们一起得到:
WITH CTE(I)
AS
(
SELECT 1 I
FROM DUAL
UNION ALL
SELECT CTE.I + 1 I
FROM CTE
WHERE CTE.I <= (SELECT MAX(REGEXP_COUNT(HIERARCHY.PATH, '/')) + 1
FROM HIERARCHY)
)
SELECT HIERARCHY.ID HIERARCHY_ID,
HIERARCHY.PATH HIERARCHY_PATH,
LISTAGG(OBJECT.NAME, '/') WITHIN GROUP (ORDER BY CTE.I) OBJECT_PATH
FROM HIERARCHY
LEFT JOIN CTE
ON CTE.I <= REGEXP_COUNT(HIERARCHY.PATH, '/') + 1
LEFT JOIN OBJECT
ON OBJECT.ID = TO_NUMBER(REGEXP_REPLACE(REGEXP_SUBSTR(HIERARCHY.PATH, '(^|/)[^/]+', 1, CTE.I), '^/'))
GROUP BY HIERARCHY.ID,
HIERARCHY.PATH
ORDER BY HIERARCHY.ID;
带CTE(一)
作为
(
选择1 I
来自双重
联合所有
选择CTE.I+1 I
来自CTE
其中CTE.I没有显示对象及其ID的表,我只有它们各自的路径。但是,我选择了这些项目,查询效果非常好(比我的7 left join hehe更好)。非常感谢!
REGEXP_REPLACE(REGEXP_SUBSTR(HIERARCHY.PATH, '(^|/)[^/]+', 1, CTE.I), '^/')
LEFT JOIN OBJECT
ON OBJECT.ID = TO_NUMBER(REGEXP_REPLACE(REGEXP_SUBSTR(HIERARCHY.PATH, '(^|/)[^/]+', 1, CTE.I), '^/'))
LISTAGG(OBJECT.NAME, '/') WITHIN GROUP (ORDER BY CTE.I) OBJECT_PATH
WITH CTE(I)
AS
(
SELECT 1 I
FROM DUAL
UNION ALL
SELECT CTE.I + 1 I
FROM CTE
WHERE CTE.I <= (SELECT MAX(REGEXP_COUNT(HIERARCHY.PATH, '/')) + 1
FROM HIERARCHY)
)
SELECT HIERARCHY.ID HIERARCHY_ID,
HIERARCHY.PATH HIERARCHY_PATH,
LISTAGG(OBJECT.NAME, '/') WITHIN GROUP (ORDER BY CTE.I) OBJECT_PATH
FROM HIERARCHY
LEFT JOIN CTE
ON CTE.I <= REGEXP_COUNT(HIERARCHY.PATH, '/') + 1
LEFT JOIN OBJECT
ON OBJECT.ID = TO_NUMBER(REGEXP_REPLACE(REGEXP_SUBSTR(HIERARCHY.PATH, '(^|/)[^/]+', 1, CTE.I), '^/'))
GROUP BY HIERARCHY.ID,
HIERARCHY.PATH
ORDER BY HIERARCHY.ID;