从SQL中的数字映射表创建树查询(带分隔符字段)

时间:2016-04-29 21:57:32

标签: sql-server-2008 tsql tree treeview hierarchical-data

我的会计软件中有一个导出的表,如下面SQL Server 2008中那样。

AccountID     AccountName     SourceCast     
---------     -----------     -----------
11            Acc11           9401
12            Acc12           9401
13            Acc13           9401
11/11         Acc11/11        9401
11/12         Acc11/12        9401
11/111        Acc11/111       9401
11/11/001     Acc11/11/001    9401
11/11/002     Acc11/11/002    9401
15            Acc15           9402
12            Acc12           9402
13            Acc13           9402
15/15         Acc15/15        9402
15/12         Acc15/12        9402
15/111        Acc15/111       9402
15/15/001     Acc15/15/001    9402
15/15/002     Acc15/15/002    9402

然后预期结果必须如下:

 AccountID     AccountName    ID   ParentID  Level   HasChild  SourceCast
 ---------     -----------    ---  --------- ------  --------  ----------
 9401          9401           1     Null       1        1      9401
 11            Acc11          2     1          2        1      9401
 12            Acc12          3     1          2        1      9401
 13            Acc13          4     1          2        0      9401
 11/11         Acc11/11       5     2          3        1      9401
 11/12         Acc11/12       6     2          3        0      9401
 11/111        Acc11/111      7     2          3        0      9401
 11/11/001     Acc11/11/001   8     5          4        0      9401
 11/11/002     Acc11/11/002   9     5          4        0      9401
 12/111        Acc12/111      10    5          3        0      9401
 12/112        Acc12/112      11    5          3        0      9401
 9402          9402           12    Null       1        1      9401
 15            Acc15          13    12         2        1      9402
 12            Acc12          14    12         2        1      9402
 13            Acc13          15    12         2        0      9402
 15/15         Acc15/15       16    13         2        1      9402
 15/12         Acc15/12       17    13         2        0      9402
 15/111        Acc15/111      18    13         3        0      9402
 15/15/001     Acc15/15/001   19    16         4        0      9402
 15/15/002     Acc15/15/002   20    16         4        0      9402
 12/111        Acc12/111      21    14         3        0      9402
 12/112        Acc12/112      22    14         3        0      9402

之前提出的这个问题没有" SourceCast"此Link中的字段由Shnugo回答。我的主表非常大,有超过30000条记录 你能帮帮我吗? 感谢。

您可以在此处找到我的样本表:

 CREATE TABLE Account(AccountID   NVARCHAR(50) NOT NULL PRIMARY KEY
  ,AccountName NVARCHAR(50) NOT NULL
  ,SourceCast  INTEGER  NOT NULL);

 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'11',N'Acc11',9401);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'12',N'Acc12',9401);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'13',N'Acc13',9401);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'11/11',N'Acc11/11',9401);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'11/12',N'Acc11/12',9401);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'11/111',N'Acc11/111',9401);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'11/11/001',N'Acc11/11/001',9401);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'11/11/002',N'Acc11/11/002',9401);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'15',N'Acc15',9402);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'12',N'Acc12',9402);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'13',N'Acc13',9402);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'15/15',N'Acc15/15',9402);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'15/12',N'Acc15/12',9402);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'15/111',N'Acc15/111',9402);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'15/15/001',N'Acc15/15/001',9402);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'15/15/002',N'Acc15/15/002',9402);

1 个答案:

答案 0 :(得分:1)

这应该让你非常接近...但我必须承认,我并不完全理解逻辑......为什么9401 / Acc12" HasChild"设为1?

试试吧。编号由SourceCast划分。这意味着,两个集合(或许多集合都被视为一个集合,具体取决于SourceCast。此外,还有一个正在运行的ID,如您的示例所示:

CREATE TABLE Account(AccountID   NVARCHAR(50) NOT NULL
  ,AccountName NVARCHAR(50) NOT NULL
  ,SourceCast  INTEGER  NOT NULL
  ,PRIMARY KEY (AccountID,SourceCast));

 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'11',N'Acc11',9401);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'12',N'Acc12',9401);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'13',N'Acc13',9401);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'11/11',N'Acc11/11',9401);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'11/12',N'Acc11/12',9401);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'11/111',N'Acc11/111',9401);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'11/11/001',N'Acc11/11/001',9401);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'11/11/002',N'Acc11/11/002',9401);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'15',N'Acc15',9402);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'12',N'Acc12',9402);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'13',N'Acc13',9402);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'15/15',N'Acc15/15',9402);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'15/12',N'Acc15/12',9402);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'15/111',N'Acc15/111',9402);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'15/15/001',N'Acc15/15/001',9402);
 INSERT INTO Account(AccountID,AccountName,SourceCast) VALUES (N'15/15/002',N'Acc15/15/002',9402);
GO

WITH DistinctSourceCasts AS (SELECT DISTINCT SourceCast FROM Account)
SELECT *
INTO #tempHierarchy
FROM
(
    SELECT SourceCast
          ,CAST(SourceCast AS NVARCHAR(50)) AS AccountID 
          ,CAST(SourceCast AS NVARCHAR(50)) AS AccountName
          ,0 AS ID
          ,0 AS HierarchyLevel
          ,'' AS ParentPath
          ,'' AS ownID
          ,'' AS ancestorID 
    FROM DistinctSourceCasts
    UNION ALL
    SELECT SourceCast
          ,AccountID
          ,AccountName
          ,ROW_NUMBER() OVER(PARTITION BY SourceCast ORDER BY LEN(AccountID)-LEN(REPLACE(AccountID,'/','')),AccountID) AS ID
          ,Extended.HierarchyLevel
          ,STUFF(
           (
             SELECT '/' + A.B.value('.','varchar(10)')
             FROM Extended.IDsXML.nodes('/x[position() <= sql:column("HierarchyLevel")]') AS A(B)
             FOR XML PATH('')
           ),1,2,'') AS ParentPath
          ,Extended.IDsXML.value('/x[sql:column("HierarchyLevel")+1][1]','varchar(10)') AS ownID
          ,Extended.IDsXML.value('/x[sql:column("HierarchyLevel")][1]','varchar(10)') AS ancestorID
    FROM Account
    CROSS APPLY(SELECT LEN(AccountID)-LEN(REPLACE(AccountID,'/','')) + 1 AS HierarchyLevel
                      ,CAST('<x></x><x>' + REPLACE(AccountID,'/','</x><x>') + '</x>' AS XML) AS IDsXML) AS Extended
) AS tbl;

UPDATE #tempHierarchy SET ParentPath = SourceCast,ancestorID=SourceCast WHERE HierarchyLevel=1;
UPDATE #tempHierarchy SET ownID=SourceCast WHERE HierarchyLevel=0;


WITH RecursiveCTE AS
(
    SELECT th.*
           ,CAST(NULL AS BIGINT) AS ParentID 
           ,CASE WHEN EXISTS(SELECT 1 FROM #tempHierarchy AS x WHERE x.ParentPath=th.AccountID) THEN 1 ELSE 0 END AS HasChild
    FROM #tempHierarchy AS th WHERE th.HierarchyLevel=0
    UNION ALL
    SELECT r.SourceCast
          ,sa.AccountID
          ,sa.AccountName
          ,sa.ID
          ,sa.HierarchyLevel
          ,sa.ParentPath
          ,sa.ownID
          ,sa.ancestorID
          ,(SELECT x.ID FROM #tempHierarchy AS x WHERE x.AccountID=sa.ParentPath)
          ,CASE WHEN EXISTS(SELECT 1 FROM #tempHierarchy AS x WHERE x.ParentPath=sa.AccountID) THEN 1 ELSE 0 END AS HasChild
    FROM RecursiveCTE AS r
    INNER JOIN #tempHierarchy AS sa ON sa.HierarchyLevel=r.HierarchyLevel+1 
                                       AND r.AccountID=sa.ParentPath
                                       AND r.SourceCast=sa.SourceCast
)
SELECT SourceCast
      ,r.AccountID
      ,r.AccountName
      ,ROW_NUMBER() OVER(ORDER BY SourceCast,HierarchyLevel,ParentID,ID) AS ID
      ,r.ID AS GroupedID
      ,r.ParentID
      ,r.HierarchyLevel
      ,r.HasChild
FROM RecursiveCTE AS r

DROP TABLE #tempHierarchy;

结果:

+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| SourceCast | AccountID | AccountName  | ID | GroupedID | ParentID | HierarchyLevel | HasChild |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9401       | 9401      | 9401         | 1  | 0         | NULL     | 0              | 1        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9401       | 11        | Acc11        | 2  | 1         | 0        | 1              | 1        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9401       | 12        | Acc12        | 3  | 2         | 0        | 1              | 0        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9401       | 13        | Acc13        | 4  | 3         | 0        | 1              | 0        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9401       | 11/11     | Acc11/11     | 5  | 4         | 1        | 2              | 1        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9401       | 11/111    | Acc11/111    | 6  | 5         | 1        | 2              | 0        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9401       | 11/12     | Acc11/12     | 7  | 6         | 1        | 2              | 0        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9401       | 11/11/001 | Acc11/11/001 | 8  | 7         | 4        | 3              | 0        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9401       | 11/11/002 | Acc11/11/002 | 9  | 8         | 4        | 3              | 0        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9402       | 9402      | 9402         | 10 | 0         | NULL     | 0              | 1        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9402       | 12        | Acc12        | 11 | 1         | 0        | 1              | 0        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9402       | 13        | Acc13        | 12 | 2         | 0        | 1              | 0        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9402       | 15        | Acc15        | 13 | 3         | 0        | 1              | 1        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9402       | 15/111    | Acc15/111    | 14 | 4         | 3        | 2              | 0        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9402       | 15/12     | Acc15/12     | 15 | 5         | 3        | 2              | 0        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9402       | 15/15     | Acc15/15     | 16 | 6         | 3        | 2              | 1        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9402       | 15/15/001 | Acc15/15/001 | 17 | 7         | 6        | 3              | 0        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+
| 9402       | 15/15/002 | Acc15/15/002 | 18 | 8         | 6        | 3              | 0        |
+------------+-----------+--------------+----+-----------+----------+----------------+----------+