我一直在使用查询来检索数据库中文件的层次结构。以下是表格的示例:
_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
。我需要的是一种检索对象的完整路径的方法(意味着/
之间的每个数字等于一个对象)。我成功地找到了某个东西的整个路径,但是在多行中。如果可能的话,我想把它放在一排。
这是我当前的查询和结果(对于第一个表中的第二个Parallel I-F
):
SELECT *
FROM WC.CLASSIFICATIONNODE
WHERE substr(HIERARCHYID, - instr(reverse(HIERARCHYID), '/') + 1) IN ('163796003', '1761551443', '413793741', '1362244494', '110367462', '391521622', '4124681422', '3222611234')
ORDER BY HIERARCHYID;
结果是:
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
如何获得Part/Electronic/Integrated Circuits/Data Acquisition/ADC/Parallel-I-F
之类的内容?
我目前正在尝试在同一个桌面上使用左连接,但没有成功。我也读过关于使用CTE的内容,但我从来没有能够成功使用它。我是SQL开发人员,但不介意其他环境答案!
答案 0 :(得分:2)
你想要的东西似乎有可能。但我无法从你的(在这方面很差)描述中完全弄清楚你的桌子结构。所以我将自己做一个演示如何做到这一点。您必须自己在模式中进行翻译。
既然你提到了SQL Developer,我想你是在使用Oracle。您还错过了标记您正在使用的DBMS。
表OBJECT
存储具有名称和ID的对象。
CREATE TABLE OBJECT
(ID NUMBER(38),
NAME VARCHAR2(8));
表HIERARCHY
将对象的路径存储为其ID的字符串,以'/'
和ID分隔。
CREATE TABLE HIERARCHY
(ID NUMBER(38),
PATH VARCHAR2(8));
现在我们首先需要的是一个数字表,其中{1}中路径中的对象的最大值为1。我们可以使用递归CTE。
HIERARCHY
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连接到MAX()
的所有行,这样HIERARCHY
的每一行都会与行路径中的对象数一样频繁出现(或者如果是path是空字符串,相当于Oracle中的HIERARCHY
。
NULL
我们再一次可以使用FROM HIERARCHY
LEFT JOIN CTE
ON CTE.I <= REGEXP_COUNT(HIERARCHY.PATH, '/') + 1
加入所有数字,这些数字小于或等于路径中的对象数。
REGEXP_COUNT(HIERARCHY.PATH, '/') + 1
现在将对CTE.I
中的行进行编号,对于路径中的每个对象,从1到1的整数到路径中的整数总数(或{{1} },如果路径是HIERARCHY
)。
我们可以在联接的结果中使用NULL
从路径中提取对象ID,即路径中NULL
个位置。为此,我们可以使用CTE.I
:
CTE.I
模式匹配所有字符,在字符串开头之后或REGEXP_SUBSTR()
之后不是REGEXP_SUBSTR(HIERARCHY.PATH, '(^|/)[^/]+', 1, CTE.I)
。第四个参数'/'
告诉函数返回'/'
- 匹配。这就是我们如何获得路径中相应位置的相关对象ID。不幸的是,在返回的匹配开头可能不需要CTE.I
,因此我们将其包装在CTE.I
中以删除它们。
'/'
有了这个,我们现在可以离开加入REGEXP_REPLACE()
。我们只需要额外添加REGEXP_REPLACE(REGEXP_SUBSTR(HIERARCHY.PATH, '(^|/)[^/]+', 1, CTE.I), '^/')
。
OBJECT
加入TO_NUMBER()
我们差不多完成了。我们现在LEFT JOIN OBJECT
ON OBJECT.ID = TO_NUMBER(REGEXP_REPLACE(REGEXP_SUBSTR(HIERARCHY.PATH, '(^|/)[^/]+', 1, CTE.I), '^/'))
输出中我们想要的OBJECT
列,例如GROUP BY
和HIERARCHY
,并使用HIERARCHY.ID
将对象名称连接到由HIERARCHY.PATH
分隔的路径。
LISTAGG()
'/'
确保每个对象名称都位于路径中的正确位置。
我们一起得到:
LISTAGG(OBJECT.NAME, '/') WITHIN GROUP (ORDER BY CTE.I) OBJECT_PATH