简单的表格示例:
CatID | ParentID | Name | DisplayOrder
============================================
1 NULL A 1
2 1 A1 1
3 1 A2 2
4 NULL B 2
etc.
我想由父母和父母的孩子订购。但我也想遵守DisplayOrder。因此,首先由父级按显示顺序,然后按每个父级内的子项,按其显示顺序。只有一层深。我希望尽可能避免复杂的查询,例如我见过的大多数CTE示例。
嗯,这可行
SELECT * FROM (
SELECT
CatID
,ParentID
,DisplayOrder AS LevelOne
,NULL AS LevelTwo
FROM Table WHERE ParentID IS NULL
UNION ALL
SELECT
c.CatID
,c.ParentID
,d.DisplayOrder AS LevelOne
,c.DisplayOrder AS LevelTwo
FROM Table c WHERE ParentID IS NOT NULL
INNER JOIN Table d ON c.ParentID = d.CatID
) AS Cats
ORDER BY Cats.LevelOne, Cats.LevelTwo
好的,所以上面的查询工作正常,但只在一个条件下...父母的DisplayOrder必须是不同的。因此,如果两个父母将1作为DisplayOrder(无论出于何种原因),那么结果集就会变得非常混乱。只要我按顺序显示父级的显示顺序,1,2,3,4,5等,然后它就可以了。我理解为什么,但试图找到解决它的最佳解决方案,并考虑重复显示订单的可能性。
答案 0 :(得分:1)
<强> SQL2008 +:强>
一种解决方案是使用嵌套集的HIERARCHYID
(最小SQL2008)数据类型将邻接列表(CatID, ParentID
)转换为嵌套集(/ParentID/.../CatID/
)。要对HIERARCHYID
值进行排序,SQL Server使用深度优先方法(父级 - >所有子级)。
DECLARE @Nodes TABLE (
CatID INT PRIMARY KEY,
ParentID INT NULL, -- FK
Name VARCHAR(50)
);
INSERT @Nodes
VALUES
(111, NULL, 'A'), (22, 111, 'A1'), (33, 111, 'A2'), (44, 111, 'A3'),
(222, NULL, 'B'), (55, 222, 'B2'), (66, 222, 'B1');
WITH RecursiveCTE
AS (
SELECT crt.CatID, crt.ParentID, crt.Name,
CONVERT(HIERARCHYID, '/'+CONVERT(VARCHAR(11), crt.CatID)+'/') AS HID
FROM @Nodes crt
WHERE crt.ParentID IS NULL
UNION ALL
SELECT crt.CatID, crt.ParentID, crt.Name,
CONVERT(HIERARCHYID, prev.HID.ToString()+CONVERT(VARCHAR(11), crt.CatID)+'/') AS HID
FROM @Nodes crt INNER JOIN RecursiveCTE prev ON crt.ParentID = prev.CatID
WHERE crt.ParentID IS NOT NULL
)
SELECT *,
HID.ToString() AS HID_ToString,
ROW_NUMBER() OVER(PARTITION BY HID.GetLevel() ORDER BY HID) AS DisplayOrder1,
ROW_NUMBER() OVER(PARTITION BY HID.GetAncestor(1) ORDER BY HID) AS DisplayOrder2,
HID.GetLevel() AS HID_Level
FROM RecursiveCTE
ORDER BY HID
OPTION (MAXRECURSION 200); -- Default MAXRECURSION value is 100
输出:
/*
CatID ParentID Name HID HID_ToString DisplayOrder1 DisplayOrder2 HID_Level
----- -------- ---- ---------- ------------ ------------- ------------- ---------
111 NULL A 0xE02FC0 /111/ 1 1 1
22 111 A1 0xE02FF074 /111/22/ 1 1 2
33 111 A2 0xE02FF24C /111/33/ 2 2 2
44 111 A3 0xE02FF2E4 /111/44/ 3 3 2
222 NULL B 0xE20F40 /222/ 2 2 1
55 222 B2 0xE20F747C /222/55/ 4 1 2
66 222 B1 0xE20F7654 /222/66/ 5 2 2
*/
答案 1 :(得分:1)
这将允许您在不跳过箍的情况下正确排序,随时更改数据类型,只需记住DisplayOrder + ' - ' + CatID
中的变量int
是否会评估为1+0+1=2
而不是'1 - 1'
CREATE TABLE #table (
CatID INT PRIMARY KEY
,ParentID INT NULL
,NAME VARCHAR(50)
,DisplayOrder INT
);
INSERT #table
VALUES (1,NULL,'A',1)
,(2,1,'A1',1)
,(3,1,'A2',2)
,(4,NULL,'B',2);
SELECT *
FROM (
SELECT CatID
,ParentID
,Convert(VARCHAR(50), DisplayOrder)
+ ' - '
+ Convert(VARCHAR(50), CatID) AS LevelOne
,NULL AS LevelTwo
FROM #table
WHERE ParentID IS NULL
UNION ALL
SELECT c.CatID
,c.ParentID
,Convert(VARCHAR(50), d.DisplayOrder)
+ ' - '
+ Convert(VARCHAR(50), d.CatID) AS LevelOne
,c.DisplayOrder AS LevelTwo
FROM #table c
INNER JOIN #table d ON c.ParentID = d.CatID
WHERE c.ParentID IS NOT NULL
) AS Cats
ORDER BY Cats.LevelOne
,Cats.LevelTwo;
DROP TABLE #table
CatID ParentID LevelOne LevelTwo
1 NULL 1 - 1 NULL
2 1 1 - 1 1
3 1 1 - 1 2
4 NULL 2 - 4 NULL
这导致:
{{1}}