我需要以特定的方式获得树的有序层次结构。有问题的表看起来有点像这样(所有ID字段都是uniqueidentifiers,为了示例,我简化了数据):
EstimateItemID EstimateID ParentEstimateItemID ItemType -------------- ---------- -------------------- -------- 1 A NULL product 2 A 1 product 3 A 2 service 4 A NULL product 5 A 4 product 6 A 5 service 7 A 1 service 8 A 4 product
树形结构的图形视图(*表示“服务”):
A ___/ \___ / \ 1 4 / \ / \ 2 7* 5 8 / / 3* 6*
使用此查询,我可以获得层次结构(只是假装'A'是一个唯一标识符,我知道它不在现实生活中):
DECLARE @EstimateID uniqueidentifier
SELECT @EstimateID = 'A'
;WITH temp as(
SELECT * FROM EstimateItem
WHERE EstimateID = @EstimateID
UNION ALL
SELECT ei.* FROM EstimateItem ei
INNER JOIN temp x ON ei.ParentEstimateItemID = x.EstimateItemID
)
SELECT * FROM temp
这给了我EstimateID'A'的孩子,但按照它出现在表格中的顺序。即:
EstimateItemID -------------- 1 2 3 4 5 6 7 8
不幸的是,我需要的是一个有序的层次结构,其结果集遵循以下约束:
1. each branch must be grouped 2. records with ItemType 'product' and parent are the top node 3. records with ItemType 'product' and non-NULL parent grouped after top node 4. records with ItemType 'service' are bottom node of a branch
所以,在这个例子中,我需要结果的顺序是:
EstimateItemID -------------- 1 2 3 7 4 5 8 6
我需要在查询中添加什么才能完成此任务?
答案 0 :(得分:75)
试试这个:
;WITH items AS (
SELECT EstimateItemID, ItemType
, 0 AS Level
, CAST(EstimateItemID AS VARCHAR(255)) AS Path
FROM EstimateItem
WHERE ParentEstimateItemID IS NULL AND EstimateID = @EstimateID
UNION ALL
SELECT i.EstimateItemID, i.ItemType
, Level + 1
, CAST(Path + '.' + CAST(i.EstimateItemID AS VARCHAR(255)) AS VARCHAR(255))
FROM EstimateItem i
INNER JOIN items itms ON itms.EstimateItemID = i.ParentEstimateItemID
)
SELECT * FROM items ORDER BY Path
使用Path
- 按父节点排序的行
如果您希望每个级别按ItemType
排序子节点,则可以使用Level
列的SUBSTRING
和Path
....
此处SQLFiddle包含数据样本
答案 1 :(得分:14)
这是Fabio从上面提出的好主意的补充。就像我在回复原帖时说的那样。我使用更常见的数据,表名和字段重新发布了他的想法,以便其他人更容易理解。
谢谢法比奥!顺便说一句好名字。
首先使用的一些数据:
CREATE TABLE tblLocations (ID INT IDENTITY(1,1), Code VARCHAR(1), ParentID INT, Name VARCHAR(20));
INSERT INTO tblLocations (Code, ParentID, Name) VALUES
('A', NULL, 'West'),
('A', 1, 'WA'),
('A', 2, 'Seattle'),
('A', NULL, 'East'),
('A', 4, 'NY'),
('A', 5, 'New York'),
('A', 1, 'NV'),
('A', 7, 'Las Vegas'),
('A', 2, 'Vancouver'),
('A', 4, 'FL'),
('A', 5, 'Buffalo'),
('A', 1, 'CA'),
('A', 10, 'Miami'),
('A', 12, 'Los Angeles'),
('A', 7, 'Reno'),
('A', 12, 'San Francisco'),
('A', 10, 'Orlando'),
('A', 12, 'Sacramento');
现在是递归查询:
-- Note: The 'Code' field isn't used, but you could add it to display more info.
;WITH MyCTE AS (
SELECT ID, Name, 0 AS TreeLevel, CAST(ID AS VARCHAR(255)) AS TreePath
FROM tblLocations T1
WHERE ParentID IS NULL
UNION ALL
SELECT T2.ID, T2.Name, TreeLevel + 1, CAST(TreePath + '.' + CAST(T2.ID AS VARCHAR(255)) AS VARCHAR(255)) AS TreePath
FROM tblLocations T2
INNER JOIN MyCTE itms ON itms.ID = T2.ParentID
)
-- Note: The 'replicate' function is not needed. Added it to give a visual of the results.
SELECT ID, Replicate('.', TreeLevel * 4)+Name 'Name', TreeLevel, TreePath
FROM MyCTE
ORDER BY TreePath;
答案 2 :(得分:0)
我认为你需要在CTE的结果中添加以下内容......
如果输出中存在这些,我认为您应该能够将查询的输出用作查询中的另一个CTE或FROM子句。按BranchID,ItemTypeID,Parent排序。