1

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

例如在下面的数据中,链接“DG”会出现多次:

╔════════════╦════════╗
║     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。

我最初的想法是使用到目前为止为每一行分配一个唯一的 ID,Row_Number() + Max(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 ║
╚═════════════╩═════════════╩═══════════╩═══════════╝

此处“DG”链接多次出现,但在每个实例中都有不同的 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上查看。

4

0 回答 0