我想为以下内容创建SQL Server查询。我有以下数据:
Id Name parentId
1 STU 0
2 XYZ 5
3 PQR 5
4 EFG 0
5 ABC 0
6 HIJ 1
7 DEF 1
以下是我正在使用的查询:
SELECT *
FROM TABLE
ORDER BY CASE WHEN parentId = 0 THEN id ELSE parentId END ASC, id ASC
输出(父级及其子级一起排序):
Id Name parentId
1 STU 0
6 HIJ 1
7 DEF 1
4 EFG 0
5 ABC 0
2 XYZ 5
3 PQR 5
现在我需要按姓名排序,首先是父母的名字,然后是所有孩子,也按姓名排序。预期的输出是:
Id Name parentId
5 ABC 0
3 PQR 5
2 XYZ 5
4 EFG 0
1 STU 0
7 DEF 1
6 HIJ 1
有人有解决方案吗?我需要严格的SQL Server查询。
P.S。只有一个层次结构。
答案 0 :(得分:2)
SQL Server中几乎每个层次结构问题都是通过递归cte解决的。
你没有提到是否可以有多个级别的层次结构,但由于没有办法阻止那个其他的,而是编写一个而不是触发器或基于udf的检查约束,我假设可以有多个层级行。
这个答案的诀窍是按字母顺序排序数字与数字排序不同的事实
如果您将1, 11, 2, 13, 21, 3
排序为数字排序,则
你会得到1, 2, 3, 11, 13, 21
但是,按按字母顺序排序排序相同的数字,
你会得到1, 11, 13, 2, 21, 3
。
现在,足够的谈话,让我们看一些代码!
首先,创建并填充样本表(请在将来的问题中保存此步骤):
DECLARE @T AS TABLE
(
Id int,
[Name] char(3),
parentId int
)
INSERT INTO @T (Id, [Name], parentId) VALUES
(1, 'STU', 0),
(2, 'XYZ', 5),
(3, 'PQR', 5),
(4, 'EFG', 0),
(5, 'ABC', 0),
(6, 'HIJ', 1),
(7, 'DEF', 1),
(8, 'AAA', 3),
(9, 'ZZZ', 3)
注意:我为孙子孙女添加了两行以检查多层次结构。
cte:
;WITH CTE AS
(
SELECT Id,
[Name],
ParentId,
-- Row_Number returns a bigint - max value have 19 digits
CAST(ROW_NUMBER() OVER(ORDER BY [Name]) as varchar(19)) As Sort
FROM @T
WHERE parentId = 0
UNION ALL
SELECT T.Id,
T.[Name],
T.ParentId,
CAST(Sort + CAST(ROW_NUMBER() OVER(ORDER BY T.[Name]) as varchar(19)) as varchar(19))
FROM @T T
JOIN CTE ON T.parentId = CTE.Id
)
查询:
SELECT Id, [Name], ParentId
FROM CTE
ORDER BY Sort -- alphabetic sort will order 11 before 2...
结果:
Id Name ParentId
5 ABC 0
3 PQR 5
8 AAA 3
9 ZZZ 3
2 XYZ 5
4 EFG 0
1 STU 0
7 DEF 1
6 HIJ 1
答案 1 :(得分:1)
试试这个
;WITH CTE
AS
(
SELECT
RN =0,
ID,
NAME,
parentId = ID
FROM T1
WHERE parentId = 0
UNION ALL
SELECT
RN = ROW_NUMBER() OVER(PARTITION BY T1.parentId ORDER BY T1.name asc),
T1.ID,
T1.NAME,
T1.parentId
FROM T1
INNER JOIN T1 T2
ON T1.parentId =T2.ID
)
SELECT
id,
name,
parentid
FROM CTE
ORDER BY parentId DESC,RN
答案 2 :(得分:1)
这是相当直接的,真的:
SELECT
category.*,
-- bring parent and its children together
CASE WHEN parent.Id IS NULL THEN category.Name ELSE parent.Name END AS sort1,
-- move parent to top followed by its children
CASE WHEN parent.Id IS NULL THEN NULL ELSE category.Name END AS sort2
FROM category
LEFT JOIN category AS parent ON category.parentId = parent.Id
ORDER BY sort1, sort2
输出:
+------+------+----------+-------+-------+
| Id | Name | parentId | sort1 | sort2 |
+------+------+----------+-------+-------+
| 5 | ABC | 0 | ABC | NULL |
| 3 | PQR | 5 | ABC | PQR |
| 2 | XYZ | 5 | ABC | XYZ |
| 4 | EFG | 0 | EFG | NULL |
| 1 | STU | 0 | STU | NULL |
| 7 | DEF | 1 | STU | DEF |
| 6 | HIJ | 1 | STU | HIJ |
+------+------+----------+-------+-------+
请注意,我已将排序计算放在SELECT
子句中,以解释它是如何工作的。
答案 3 :(得分:1)
如果您不了解孩子的深度,我通常会用动态Sql来解决这个问题。但是因为你似乎只有一个深度级别为2的简单版本,所以这可能有效:
declare @tempT table(ID int, name varchar(3), parentID int, sortLevel1 int, sortlevel2 int)
insert into @tempT
select t1.ID,t1.name,t1.parentID,RowNumber() Over(order by (select null)),-1
from table t1
where parentId=0
order by t1.name
insert into @tempT
select t2.ID,t2.name,t2.parentID,t1.sortLevel1,RowNumber() Over(order by (select null))
from table t1
join @tempT t2 on t1.id=t2.parentID
order by t2.name
select * from @temp order by t1.sortLevel1, sortLevel2
答案 4 :(得分:0)
在进行一些调试之后,我发现,如果其中一个层次结构级别具有> 9个条目,则Zohar Peled
的解决方案将失败。我通过修改他的代码解决了这一问题,他在代码中添加了前导零来构造“排序”列。
;WITH CTE AS
(
SELECT Id,
[Name],
ParentId,
-- Row_Number returns a bigint - max value have 19 digits
CAST(FORMAT(ROW_NUMBER() OVER(ORDER BY [Name]), 'D4') as varchar(12)) As Sort
FROM @T
WHERE parentId = 0
UNION ALL
SELECT T.Id,
T.[Name],
T.ParentId,
CAST(Sort + CAST(FORMAT(ROW_NUMBER() OVER(ORDER BY [Name]), 'D4') as varchar(4)) as varchar(12))
FROM @T T
JOIN CTE ON T.parentId = CTE.Id
)
就我而言,我不需要超过4个字符。但是,如果您需要更多,只需自己添加即可,不要忘记根据层次结构中的级别数乘以所需字符的长度来更改“排序”列的长度。