SQL ORDER BY 有例外
SQL ORDER BY with exceptions
我想按 3 列(优先级、预期日期、创建日期)对(子 select 的结果)进行排序,但是对于几行排序应该以不同的方式工作。
很难用文字描述所以我准备了一张图片:
列 排名 在 之前 table 现在是:
ROW_NUMBER() OVER(ORDER BY Priority DESC, ExpectedDate DESC, CreateDate ASC) AS [Rank],
如您所见,ShouldBeAfter 列指示 ID,无论排序如何,该行都应始终出现在该行之后。
如何编写查询以达到After的状态?
编辑 1:
示例数据:
DECLARE @Queue TABLE
(
[ChildID] INT,
[ParentID] INT,
[No] INT,
[Change] INT,
[Priority] INT,
[ExpectedDate] DATETIME,
[CreateDate] DATETIME
)
INSERT INTO @Queue VALUES (242, 0, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-11-27 15:08:40.677')
INSERT INTO @Queue VALUES (243, 274, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-11-27 15:22:46.350')
INSERT INTO @Queue VALUES (244, 0, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-11-27 15:29:52.010')
INSERT INTO @Queue VALUES (259, 0, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-11-30 15:54:48.710')
INSERT INTO @Queue VALUES (261, 0, 0, 0, 4, '1900-01-01 00:00:00.000', '2015-12-01 11:07:32.357')
INSERT INTO @Queue VALUES (263, 0, 0, 0, 5, '1900-01-01 00:00:00.000', '2015-12-02 12:07:01.980')
INSERT INTO @Queue VALUES (264, 0, 0, 0, 2, '1900-01-01 00:00:00.000', '2015-12-03 14:58:19.717')
INSERT INTO @Queue VALUES (266, 0, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-12-08 09:55:06.277')
INSERT INTO @Queue VALUES (269, 0, 0, 0, 3, '2015-12-16 00:00:00.000', '2015-12-08 17:53:24.820')
INSERT INTO @Queue VALUES (270, 0, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-12-09 15:50:37.970')
INSERT INTO @Queue VALUES (272, 0, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-12-11 12:06:19.253')
INSERT INTO @Queue VALUES (273, 242, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-12-11 12:08:20.010')
INSERT INTO @Queue VALUES (274, 0, 0, 0, 2, '1900-01-01 00:00:00.000', '2015-12-11 12:09:00.200')
INSERT INTO @Queue VALUES (275, 0, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-12-11 12:14:50.110')
INSERT INTO @Queue VALUES (276, 0, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-12-11 12:17:49.220')
INSERT INTO @Queue VALUES (277, 0, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-12-11 12:24:28.823')
INSERT INTO @Queue VALUES (278, 0, 0, 0, 5, '2015-12-10 00:00:00.000', '2015-12-11 12:27:53.803')
INSERT INTO @Queue VALUES (279, 0, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-12-11 12:32:14.397')
INSERT INTO @Queue VALUES (280, 0, 0, 0, 2, '1900-01-01 00:00:00.000', '2015-12-11 13:56:06.080')
INSERT INTO @Queue VALUES (281, 0, 0, 0, 2, '1900-01-01 00:00:00.000', '2015-12-15 10:16:35.057')
INSERT INTO @Queue VALUES (282, 276, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-12-15 10:18:50.180')
INSERT INTO @Queue VALUES (284, 0, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-12-15 11:33:33.553')
这有点麻烦,因为您需要一个额外的连接:
select t.*
from t left join
t2
on t.id = t2.shouldbeafter
order by coalesce(t2.shouldbeafter, t.id),
t.shouldbeafter, t.id;
注意:这适用于一个级别,但不适用于多个级别。
您可以使用 CTE 分两步完成:
;WITH InitialRank AS (
SELECT *,
ROW_NUMBER() OVER(ORDER BY Priority DESC,
ExpectedDate DESC,
CreateDate ASC) AS [Rank]
FROM Queue
), FinalRank AS (
SELECT t1.ID, t1.ShouldBeAfter, t1.No, t1.Change,
t1.Priority, t1.ExpectedDate, t1.CreateDate,
COALESCE(CAST(t2.Rank AS DECIMAL(4,1)) + 0.5, t1.Rank) AS Rank
FROM InitialRank AS t1
LEFT JOIN InitialRank AS t2
ON t1.ShouldBeAfter <> 0 AND t1.ShouldBeAfter = t2.ID
)
SELECT ID, ShouldBeAfter, No, Change,
Priority, ExpectedDate, CreateDate,
ROW_NUMBER() OVER (ORDER BY Rank) AS Rank
FROM FinalRank
ORDER BY Rank
- 第一步计算由 3 列
(Priority, ExpectedDate, CreateDate)
定义的 'initial' 排名。
- 第二步更改具有非零
ShouldBeAfter
值的所有行的排名:排名的新值是 'comes before' 行的排名加上 0.5
,因此该行将 排在 之后 'comes before' 行。
注意:只要只有单级依赖项,上面的方法就可以工作。
无需显式连接即可完成相同操作的另一种方法:
SELECT *,
MIN(CASE WHEN ShouldBeAfter = 0 THEN PreRank END)
OVER(PARTITION BY CASE WHEN ShouldBeAfter = 0 THEN ID ELSE ShouldBeAfter END) AS [Rank]
FROM (
SELECT *,
ROW_NUMBER() OVER(ORDER BY Priority DESC, ExpectedDate DESC, CreateDate ASC) AS [PreRank]
FROM Queue
)A
ORDER BY [Rank], ShouldBeAfter
我想按 3 列(优先级、预期日期、创建日期)对(子 select 的结果)进行排序,但是对于几行排序应该以不同的方式工作。
很难用文字描述所以我准备了一张图片:
列 排名 在 之前 table 现在是:
ROW_NUMBER() OVER(ORDER BY Priority DESC, ExpectedDate DESC, CreateDate ASC) AS [Rank],
如您所见,ShouldBeAfter 列指示 ID,无论排序如何,该行都应始终出现在该行之后。
如何编写查询以达到After的状态?
编辑 1:
示例数据:
DECLARE @Queue TABLE
(
[ChildID] INT,
[ParentID] INT,
[No] INT,
[Change] INT,
[Priority] INT,
[ExpectedDate] DATETIME,
[CreateDate] DATETIME
)
INSERT INTO @Queue VALUES (242, 0, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-11-27 15:08:40.677')
INSERT INTO @Queue VALUES (243, 274, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-11-27 15:22:46.350')
INSERT INTO @Queue VALUES (244, 0, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-11-27 15:29:52.010')
INSERT INTO @Queue VALUES (259, 0, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-11-30 15:54:48.710')
INSERT INTO @Queue VALUES (261, 0, 0, 0, 4, '1900-01-01 00:00:00.000', '2015-12-01 11:07:32.357')
INSERT INTO @Queue VALUES (263, 0, 0, 0, 5, '1900-01-01 00:00:00.000', '2015-12-02 12:07:01.980')
INSERT INTO @Queue VALUES (264, 0, 0, 0, 2, '1900-01-01 00:00:00.000', '2015-12-03 14:58:19.717')
INSERT INTO @Queue VALUES (266, 0, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-12-08 09:55:06.277')
INSERT INTO @Queue VALUES (269, 0, 0, 0, 3, '2015-12-16 00:00:00.000', '2015-12-08 17:53:24.820')
INSERT INTO @Queue VALUES (270, 0, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-12-09 15:50:37.970')
INSERT INTO @Queue VALUES (272, 0, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-12-11 12:06:19.253')
INSERT INTO @Queue VALUES (273, 242, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-12-11 12:08:20.010')
INSERT INTO @Queue VALUES (274, 0, 0, 0, 2, '1900-01-01 00:00:00.000', '2015-12-11 12:09:00.200')
INSERT INTO @Queue VALUES (275, 0, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-12-11 12:14:50.110')
INSERT INTO @Queue VALUES (276, 0, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-12-11 12:17:49.220')
INSERT INTO @Queue VALUES (277, 0, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-12-11 12:24:28.823')
INSERT INTO @Queue VALUES (278, 0, 0, 0, 5, '2015-12-10 00:00:00.000', '2015-12-11 12:27:53.803')
INSERT INTO @Queue VALUES (279, 0, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-12-11 12:32:14.397')
INSERT INTO @Queue VALUES (280, 0, 0, 0, 2, '1900-01-01 00:00:00.000', '2015-12-11 13:56:06.080')
INSERT INTO @Queue VALUES (281, 0, 0, 0, 2, '1900-01-01 00:00:00.000', '2015-12-15 10:16:35.057')
INSERT INTO @Queue VALUES (282, 276, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-12-15 10:18:50.180')
INSERT INTO @Queue VALUES (284, 0, 0, 0, 3, '1900-01-01 00:00:00.000', '2015-12-15 11:33:33.553')
这有点麻烦,因为您需要一个额外的连接:
select t.*
from t left join
t2
on t.id = t2.shouldbeafter
order by coalesce(t2.shouldbeafter, t.id),
t.shouldbeafter, t.id;
注意:这适用于一个级别,但不适用于多个级别。
您可以使用 CTE 分两步完成:
;WITH InitialRank AS (
SELECT *,
ROW_NUMBER() OVER(ORDER BY Priority DESC,
ExpectedDate DESC,
CreateDate ASC) AS [Rank]
FROM Queue
), FinalRank AS (
SELECT t1.ID, t1.ShouldBeAfter, t1.No, t1.Change,
t1.Priority, t1.ExpectedDate, t1.CreateDate,
COALESCE(CAST(t2.Rank AS DECIMAL(4,1)) + 0.5, t1.Rank) AS Rank
FROM InitialRank AS t1
LEFT JOIN InitialRank AS t2
ON t1.ShouldBeAfter <> 0 AND t1.ShouldBeAfter = t2.ID
)
SELECT ID, ShouldBeAfter, No, Change,
Priority, ExpectedDate, CreateDate,
ROW_NUMBER() OVER (ORDER BY Rank) AS Rank
FROM FinalRank
ORDER BY Rank
- 第一步计算由 3 列
(Priority, ExpectedDate, CreateDate)
定义的 'initial' 排名。 - 第二步更改具有非零
ShouldBeAfter
值的所有行的排名:排名的新值是 'comes before' 行的排名加上0.5
,因此该行将 排在 之后 'comes before' 行。
注意:只要只有单级依赖项,上面的方法就可以工作。
无需显式连接即可完成相同操作的另一种方法:
SELECT *,
MIN(CASE WHEN ShouldBeAfter = 0 THEN PreRank END)
OVER(PARTITION BY CASE WHEN ShouldBeAfter = 0 THEN ID ELSE ShouldBeAfter END) AS [Rank]
FROM (
SELECT *,
ROW_NUMBER() OVER(ORDER BY Priority DESC, ExpectedDate DESC, CreateDate ASC) AS [PreRank]
FROM Queue
)A
ORDER BY [Rank], ShouldBeAfter