从 SQL 中的数值映射 Table 创建树查询

Create Tree Query From Numeric Mapping Table in SQL

我有一个从会计软件导出的 table,如下所示。

 AccountID     AccountName    
 ---------     -----------
 11            Acc11
 12            Acc12
 13            Acc13
 11/11         Acc11/11
 11/12         Acc11/12
 11/111        Acc11/111
 11/11/001     Acc11/11/001
 11/11/002     Acc11/11/002
 12/111        Acc12/111
 12/112        Acc12/112

然后我想将其转换为 MS-Sql Server 2008 中的树查询,以在我的 win 应用程序中用作 Treelist 数据源。

预期SQL查询结果:

 AccountID     AccountName    ID   ParentID  Level   HasChild
 ---------     -----------    ---  --------- ------  --------
 11            Acc11          1     Null       1        1
 12            Acc12          2     Null       1        1
 13            Acc13          3     Null       1        0
 11/11         Acc11/11       4     1          2        1
 11/12         Acc11/12       5     1          2        0
 11/111        Acc11/111      6     1          2        0
 11/11/001     Acc11/11/001   7     4          3        0
 11/11/002     Acc11/11/002   8     4          3        0
 12/111        Acc12/111      9     2          2        0
 12/112        Acc12/112      10    2          2        0

你能帮我创建 SQL 查询吗? 谢谢

你可以看看 HIERARCHYID... http://searchsqlserver.techtarget.com/tip/How-to-use-SQL-Server-2008-hierarchyid-data-type

但这是一种方法...

DECLARE @tbl TABLE( AccountID  VARCHAR(100), AccountName VARCHAR(100));
INSERT INTO @tbl VALUES 
 ('11','Acc11')
,('12','Acc12')
,('13','Acc13')
,('11/11','Acc11/11')
,('11/12','Acc11/12')
,('11/111','Acc11/111')
,('11/11/001','Acc11/11/001')
,('11/11/002','Acc11/11/002')
,('12/111','Acc12/111')
,('12/112','Acc12/112');

WITH shreddAccountID AS
(
    SELECT AccountName,AccountID
          ,ROW_NUMBER() OVER(ORDER BY LEN(AccountID)-LEN(REPLACE(AccountID,'/','')),AccountID) AS ID
          ,LEN(AccountID)-LEN(REPLACE(AccountID,'/','')) + 1 As [Level]
          ,CAST('<x>' + REPLACE(AccountID,'/','</x><x>') + '</x>' AS XML) AS Shredded
    FROM @tbl
)
,RecursiveCTE AS
(
    SELECT AccountID,AccountName,ID,[Level],Shredded.value('/x[sql:column("Level")][1]','int') AS innerID,CAST(NULL AS BIGINT) AS ParentID 
    FROM shreddAccountID WHERE [Level]=1
    UNION ALL
    SELECT sa.AccountID,sa.AccountName,sa.ID,sa.[Level],sa.Shredded.value('/x[sql:column("sa.Level")][1]','int'),r.ID
    FROM RecursiveCTE AS r
    INNER JOIN shreddAccountID AS sa ON sa.Level=r.Level+1 
                                        AND r.innerID=sa.Shredded.value('/x[sql:column("sa.Level")-1][1]','int')
)
SELECT r.AccountID
      ,r.AccountName
      ,r.ID
      ,r.ParentID
      ,r.[Level]
      ,CASE WHEN EXISTS(SELECT 1 FROM RecursiveCTE AS x WHERE r.ID = x.ParentID) THEN 1 ELSE 0 END AS HasChild
FROM RecursiveCTE AS r
ORDER BY [Level],ParentID

结果

+-----------+--------------+----+----------+-------+----------+
| AccountID | AccountName  | ID | ParentID | Level | HasChild |
+-----------+--------------+----+----------+-------+----------+
| 11        | Acc11        | 1  | NULL     | 1     | 1        |
+-----------+--------------+----+----------+-------+----------+
| 12        | Acc12        | 2  | NULL     | 1     | 1        |
+-----------+--------------+----+----------+-------+----------+
| 13        | Acc13        | 3  | NULL     | 1     | 0        |
+-----------+--------------+----+----------+-------+----------+
| 11/11     | Acc11/11     | 4  | 1        | 2     | 1        |
+-----------+--------------+----+----------+-------+----------+
| 11/111    | Acc11/111    | 5  | 1        | 2     | 0        |
+-----------+--------------+----+----------+-------+----------+
| 11/12     | Acc11/12     | 6  | 1        | 2     | 0        |
+-----------+--------------+----+----------+-------+----------+
| 12/111    | Acc12/111    | 7  | 2        | 2     | 0        |
+-----------+--------------+----+----------+-------+----------+
| 12/112    | Acc12/112    | 8  | 2        | 2     | 0        |
+-----------+--------------+----+----------+-------+----------+
| 11/11/001 | Acc11/11/001 | 9  | 4        | 3     | 0        |
+-----------+--------------+----+----------+-------+----------+
| 11/11/002 | Acc11/11/002 | 10 | 4        | 3     | 0        |
+-----------+--------------+----+----------+-------+----------+

毫无疑问,无论您编写什么查询或 DBA 做什么,您的查询都会因为错误的 table 结构而变慢。

我相信您的上述查询也适用于其他示例数据。

在这种情况下,我会像(c# 等)一样在前端获取我的记录并在那里进行操作以获得所需的输出,在这种情况下通常很快。

我已经尝试用自己的方式编写查询,希望它对 6000 来说很快records.Also请也测试我对其他示例数据的查询。

我找到 LASTINdexOf("/") 然后加入

DECLARE @FilePath VARCHAR(50) = '11/11/001'
DECLARE @FindChar1 VARCHAR(1) = '/'

SELECT substring (@FilePath,0, LEN(@FilePath) - CHARINDEX(@FindChar1,REVERSE(@FilePath))+1 )AS LastOccuredAt

最终查询,

DECLARE @tbl TABLE(id int identity(1,1), AccountID  VARCHAR(100), AccountName VARCHAR(100));
INSERT INTO @tbl VALUES 
 ('11','Acc11')
,('12','Acc12')
,('13','Acc13')
,('11/11','Acc11/11')
,('11/12','Acc11/12')
,('11/111','Acc11/111')
,('11/11/001','Acc11/11/001')
,('11/11/002','Acc11/11/002')
,('12/111','Acc12/111')
,('12/112','Acc12/112');


DECLARE @FindChar VARCHAR(1) = '/'


    SELECT a.id
        ,a.accountid
        ,a.AccountName
        ,(
            SELECT min(c.id)
            FROM @tbl c
            WHERE c.id < a.id
                AND substring(a.accountid, 0, LEN(a.accountid) - CHARINDEX(@FindChar, REVERSE(a.accountid)) + 1) = c.accountid
            ) ParentID
        ,LEN(a.AccountID) - LEN(REPLACE(a.AccountID, '/', '')) + 1 AS [level]
        ,(
            SELECT CASE 
                    WHEN min(c.id) IS NOT NULL
                        THEN 1
                    ELSE 0
                    END
            FROM @tbl c
            WHERE c.id > a.id
                AND substring(c.accountid, 0, LEN(c.accountid) - CHARINDEX(@FindChar, REVERSE(c.accountid)) + 1) = a.accountid
            ) Haschild
    FROM @tbl a
    INNER JOIN @tbl b ON a.id = b.id + 1