具有多个节点的递归CTE层次结构中每行的唯一ID

时间:2012-09-30 10:41:01

标签: sql-server recursive-query

我有一个包含一组构成层次结构的链接的表。最大的问题是每个链接可能会被使用多次(在不同的位置)。我需要能够区分每个节点的每个“实例”。

例如,在以下数据中,链接“D-G”将多次显示:

╔════════════╦════════╗
║     SOURCE ║ TARGET ║
╠════════════╬════════╣
║     A      ║ B      ║
║     A      ║ C      ║
║     B      ║ D      ║
║     B      ║ E      ║
║     B      ║ F      ║
║     C      ║ D      ║
║     C      ║ E      ║
║     C      ║ F      ║
║     D      ║ G      ║
║     E      ║ D      ║
║     F      ║ D      ║
╚════════════╩════════╝

我可以使用递归CTE构建层次结构而没有任何问题,但我想给结果中的每一行一个唯一的ID并将其链接到父节点的唯一ID。

我最初的想法是使用Row_Number() + Max(ID)为每一行分配一个唯一的ID,并让该行继承它的父母ID,但是进一步阅读和试用&错误表明这不起作用: - (

有没有人知道如何解决这个问题(或至少给我一个线索)?

结果应该是这样的:

╔═════════════╦═════════════╦═══════════╦═══════════╗
║ SOURCE_DESC ║ TARGET_DESC ║ Source_ID ║ Target_ID ║
╠═════════════╬═════════════╬═══════════╬═══════════╣
║     A       ║ B           ║         0 ║         1 ║
║     A       ║ C           ║         0 ║         2 ║
║     B       ║ D           ║         1 ║         6 ║
║     B       ║ E           ║         1 ║         7 ║
║     B       ║ F           ║         1 ║         8 ║
║     C       ║ D           ║         2 ║         3 ║
║     C       ║ E           ║         2 ║         4 ║
║     C       ║ F           ║         2 ║         5 ║
║     D       ║ G           ║         3 ║        13 ║
║     E       ║ D           ║         4 ║        11 ║
║     F       ║ D           ║         5 ║        10 ║
║     D       ║ G           ║         6 ║        14 ║
║     E       ║ D           ║         7 ║        12 ║
║     F       ║ D           ║         8 ║         9 ║
║     D       ║ G           ║         9 ║        18 ║
║     D       ║ G           ║        10 ║        17 ║
║     D       ║ G           ║        11 ║        16 ║
║     D       ║ G           ║        12 ║        15 ║
╚═════════════╩═════════════╩═══════════╩═══════════╝

此处“D-G”链接会多次显示,但在每个实例中,它都有不同的ID和不同的父ID!

我设法做到了,但我对自己的方式感到不满意。它看起来效率不高(对于这个例子来说并不重要,但对于更大的集合来说非常重要!)

WITH JUNK_DATA 
     AS (SELECT *, 
                ROW_NUMBER() 
                  OVER ( 
                    ORDER BY SOURCE) RN 
         FROM   LINKS), 
     RECUR 
     AS (SELECT T1.SOURCE, 
                T1.TARGET, 
                CAST('ROOT' AS VARCHAR(MAX))      NAME, 
                1                                 AS RAMA, 
                CAST(T1.RN AS VARCHAR(MAX)) + ',' AS FULL_RAMA 
         FROM   JUNK_DATA T1 
                LEFT JOIN JUNK_DATA T2 
                       ON T1.SOURCE = T2.TARGET 
         WHERE  T2.TARGET IS NULL 
         UNION ALL 
         SELECT JUNK_DATA.SOURCE, 
                JUNK_DATA.TARGET, 
                CASE 
                  WHEN RAMA = 1 THEN (SELECT [DESC] 
                                      FROM   NAMES 
                                      WHERE  ID = JUNK_DATA.SOURCE) 
                  ELSE NAME 
                END      NAME, 
                RAMA + 1 AS RAMA, 
                FULL_RAMA 
                + CAST(JUNK_DATA.RN AS VARCHAR(MAX)) + ',' 
         FROM   (SELECT * 
                 FROM   JUNK_DATA)JUNK_DATA 
                INNER JOIN (SELECT * 
                            FROM   RECUR) RECUR 
                        ON JUNK_DATA.SOURCE = RECUR.TARGET), 
     FINAL_DATA 
     AS (SELECT T2.[DESC]          SOURCE_DESC, 
                T3.[DESC]          TARGET_DESC, 
                RECUR.*, 
                ROW_NUMBER() 
                  OVER ( 
                    ORDER BY RAMA) ID 
         FROM   RECUR 
                INNER JOIN NAMES T2 
                        ON RECUR.SOURCE = T2.ID 
                INNER JOIN NAMES T3 
                        ON RECUR.TARGET = T3.ID) 
SELECT T1.SOURCE_DESC, 
       T1.TARGET_DESC, 
       ISNULL(T2.ID, 0) AS SOURCE_ID, 
       T1.ID            TARGET_ID 
FROM   FINAL_DATA T1 
       LEFT JOIN (SELECT ID, 
                         FULL_RAMA 
                  FROM   FINAL_DATA)T2 
              ON LEFT(T1.FULL_RAMA, LEN(T1.FULL_RAMA) - CHARINDEX(',', 
                 REVERSE(T1.FULL_RAMA), 2)) 
                 + ',' = T2.FULL_RAMA 
ORDER  BY SOURCE_ID, 
          TARGET_ID 

SQL fiddle上查看。

0 个答案:

没有答案