检索表中的层次结构

时间:2018-06-08 18:38:03

标签: sql oracle

我一直在使用查询来检索数据库中文件的层次结构。以下是表格的示例:

_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开发人员,但不介意其他环境答案!

1 个答案:

答案 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 BYHIERARCHY,并使用HIERARCHY.ID将对象名称连接到由HIERARCHY.PATH分隔的路径。

LISTAGG()

'/'确保每个对象名称都位于路径中的正确位置。

我们一起得到:

LISTAGG(OBJECT.NAME, '/') WITHIN GROUP (ORDER BY CTE.I) OBJECT_PATH

db<>fiddle