假设我有一个名为Events
的表,其数据类似于以下内容:
ID | Name | ParentEvent
----+----------------+-----------------
0 | Happy Event | NULL
1 | Sad Event | NULL
2 |Very Happy Event| 0
3 | Very Sad Event | 1
4 | Happiest Event | 2
5 |Unpleasant Event| 1
如何查询此表以获得以
方式返回的结果ParentEvent
的事件会在事件发生后直接显示ID
数学ParentEvent
ParentEvent
的事件的深度为0.如果事件的深度为 n ,则其为父项的任何事件的深度为 n + 1 。对于上面给出的表,我想得到一个看起来像
的结果集 ID | Name | ParentEvent | Depth |
----+----------------+--------------+--------+
0 | Happy Event | NULL | 0 |
2 |Very Happy Event| 0 | 1 |
4 | Happiest Event | 2 | 2 |
1 | Sad Event | NULL | 0 |
3 | Very Sad Event | 1 | 1 |
5 |Unpleasant Event| 1 | 1 |
如何构造SQL查询以获取此结果集?我正在使用T-SQL,但如果您可以在任何SQL风格中执行此操作,请继续回答。
答案 0 :(得分:8)
以下查询都会返回您要求的确切结果集。所有这些工作都是通过计算根节点的完整路径,并使用一些技术使该路径能够被排序。
SQL Server 2008及更高版本。在这里,通过转换为hierarchyid
数据类型,SQL Server可以正确处理排序。
WITH Data AS (
SELECT
ID,
Name,
ParentID,
Depth = 0,
Ancestry = '/' + Convert(varchar(max), ID) + '/'
FROM
hierarchy
WHERE
ParentID IS NULL
UNION ALL
SELECT
H.ID,
H.Name,
H.ParentID,
D.Depth + 1,
Ancestry = D.Ancestry + Convert(varchar(max), H.ID) + '/'
FROM
Data D
INNER JOIN hierarchy H
ON H.ParentID = D.ID
)
SELECT
ID,
Name,
ParentID,
Depth
FROM Data
ORDER BY Convert(hierarchyid, Ancestry);
SQL Server 2005及更高版本。我们可以将ID值转换为字符串并填充它们以便排序。
WITH Data AS (
SELECT
ID,
Name,
ParentID,
Depth = 0,
Ancestry = Right('0000000000' + Convert(varchar(max), ID), 10)
FROM
hierarchy
WHERE
ParentID IS NULL
UNION ALL
SELECT
H.ID,
H.Name,
H.ParentID,
Depth + 1,
Ancestry = D.Ancestry + Right('0000000000' + Convert(varchar(max), H.ID), 10)
FROM
Data D
INNER JOIN hierarchy H
ON H.ParentID = D.ID
)
SELECT
ID,
Name,
ParentID,
Depth
FROM Data
ORDER BY Ancestry;
我们也可以使用varbinary
(否则,这与先前的查询相同):
WITH Data AS (
SELECT
ID,
Name,
ParentID,
Depth = 0,
Ancestry = Convert(varbinary(max), Convert(varbinary(4), ID))
FROM
hierarchy
WHERE
ParentID IS NULL
UNION ALL
SELECT
H.ID,
H.Name,
H.ParentID,
Depth + 1,
Ancestry = D.Ancestry + Convert(varbinary(4), H.ID)
FROM
Data D
INNER JOIN hierarchy H
ON H.ParentID = D.ID
)
SELECT
ID,
Name,
ParentID,
Depth
FROM Data
ORDER BY Ancestry;
SQL Server 2000及更高版本,允许树最多深度为800级:
SELECT
*,
Ancestry = CASE WHEN ParentID IS NULL THEN Convert(varchar(8000), Right('0000000000' + Convert(varchar(10), ID), 10)) ELSE '' END,
Depth = 0
INTO #hierarchy
FROM hierarchy;
WHILE @@RowCount > 0 BEGIN
UPDATE H
SET
H.Ancestry = P.Ancestry + Right('0000000000' + Convert(varchar(8000), H.ID), 10),
H.Depth = P.Depth + 1
FROM
#hierarchy H
INNER JOIN #hierarchy P
ON H.ParentID = P.ID
WHERE
H.Ancestry = ''
AND P.Ancestry <> '';
END;
SELECT
ID,
Name,
ParentID,
Depth
FROM #hierarchy
ORDER BY Ancestry;
DROP TABLE #hierarchy;
可以进行相同的varbinary
转换,最多允许2000级。
答案 1 :(得分:1)
这只是增加M.Ali的答案。我意识到OP说,“只要结果满足前两个条件,结果出现的顺序无关紧要”。但是,通过向查询中添加一个跟踪层次结构路径的列,可以显示与问题中相同的结果。
;WITH CTE
AS
(
SELECT
ID,
NAME,
ParentID,
0 as Depth,
convert(varbinary(max), convert(varbinary(2), ID)) as ThePath
FROM hierarchy
WHERE ParentID is null
UNION ALL
SELECT
h.ID,
h.NAME,
h.ParentID,
cte.Depth + 1,
cte.ThePath + convert(varbinary(max), convert(varbinary(2), h.ID)) as ThePath
FROM hierarchy AS h
INNER JOIN CTE as cte
ON h.ParentID = cte.ID
)
SELECT
ID,
NAME,
ParentID,
Depth,
ThePath
FROM CTE
ORDER BY ThePath
这会显示如下结果。
ID NAME ParentID Depth ThePath
----------- ------------------------------ ----------- ----------- ---------------
0 Happy Event NULL 0 0x0000
2 Very Happy Event 0 1 0x00000002
4 Happiest Event 2 2 0x000000020004
1 Sad Event NULL 0 0x0001
3 Very Sad Event 1 1 0x00010003
5 Unpleasant Event 1 1 0x00010005
答案 2 :(得分:-2)
测试数据
CREATE TABLE hierarchy (ID INT, NAME NVARCHAR(30), ParentID INT)
INSERT INTO hierarchy VALUES
(0,'Happy Event' ,NULL),
(1,'Sad Event' ,NULL),
(2,'Very Happy Event',0),
(3,'Very Sad Event' ,1),
(4,'Happiest Event' ,2),
(5,'Unpleasant Event',1)
查询(Sql Server 2005 +)
;WITH ClassHierarchy_CTE (CID, ClassID_Join, Level)
AS
(
SELECT ID, ID AS Join_Class, 0
FROM hierarchy AS c
UNION ALL
SELECT cte.CID, h.ParentID, Level + 1
FROM hierarchy AS h INNER JOIN ClassHierarchy_CTE as cte
ON h.ID = cte.ClassID_Join
)
SELECT CTE.CID AS ID
, Hic.NAME AS NAME
, Hic.ParentID AS ParentEvent
, COUNT(*)-1 AS Depth
FROM ClassHierarchy_CTE CTE INNER JOIN hierarchy Hic
ON CTE.CID = Hic.ID
WHERE ClassID_Join IS NOT NULL
GROUP BY CTE.CID, Hic.NAME, Hic.ParentID
结果集
╔════╦══════════════════╦═════════════╦═══════╗
║ ID ║ NAME ║ ParentEvent ║ Depth ║
╠════╬══════════════════╬═════════════╬═══════╣
║ 0 ║ Happy Event ║ NULL ║ 0 ║
║ 1 ║ Sad Event ║ NULL ║ 0 ║
║ 2 ║ Very Happy Event ║ 0 ║ 1 ║
║ 3 ║ Very Sad Event ║ 1 ║ 1 ║
║ 4 ║ Happiest Event ║ 2 ║ 2 ║
║ 5 ║ Unpleasant Event ║ 1 ║ 1 ║
╚════╩══════════════════╩═════════════╩═══════╝