从 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
我有一个从会计软件导出的 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