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;