Sql 基于旋转排序数据
假设我有一个数据集: 我下一个订单 1456 1679 1 1679 1679 2 1578 1679 3 9492 1679 4 此数据集中唯一更改的列是NEXT。ID始终是唯一的,下一个始终与单个ID相关,并将在每一行中重复。顺序是一个顺序整数 我需要一个orderby或其他SQL语句来执行以下排序: 下一个ID始终位于订单的底部 在NEXT的顺序之后具有顺序更高顺序的ID始终位于顶部 然后按顺序进行排序,从第二行到第一行的顺序是在第一行的顺序之后的下一行 例如: 对于上表,订购将为 1578 9492 1456 1679年 next已更改的另一个表: 我下一个订单 1456 1578 1 1679 1578 2 1578 1578 3 9492 1578 4 将是: 9492 1456 1679 1578 Fiddle使用Postgresql,因为Sql Server目前似乎已经崩溃 Fiddle使用Postgresql,因为Sql Server目前似乎已崩溃。这应该可以: 样本数据:Sql 基于旋转排序数据,sql,sql-server,database,sorting,Sql,Sql Server,Database,Sorting,假设我有一个数据集: 我下一个订单 1456 1679 1 1679 1679 2 1578 1679 3 9492 1679 4 此数据集中唯一更改的列是NEXT。ID始终是唯一的,下一个始终与单个ID相关,并将在每一行中重复。顺序是一个顺序整数 我需要一个orderby或其他SQL语句来执行以下排序: 下一个ID始终位于订单的底部 在NEXT的顺序之后具有顺序更高顺序的ID始终位于顶部 然后按顺序进行排序,从第二行到第一行的顺序是在第一行的顺序之后的下一行 例如: 对于上
IF OBJECT_ID('tempdb..#temp') IS NOT NULL
DROP TABLE #temp;
CREATE TABLE #temp(ID INT
, [NEXT] INT
, [ORDER] INT);
INSERT INTO #temp
VALUES
(1456
, 1679
, 1),
(1679
, 1679
, 2),
(1578
, 1679
, 3),
(9492
, 1679
, 4);
查询:
DECLARE @rowcount INT;
SELECT @rowcount = COUNT(1)
FROM #temp
WHERE [ORDER] >
(SELECT [ORDER]
FROM #temp
WHERE ID = [NEXT]);
SELECT ID
FROM
(SELECT *
, rn = ROW_NUMBER() OVER(ORDER BY [ORDER])
FROM #temp
WHERE [ORDER] >
(SELECT [ORDER]
FROM #temp
WHERE ID = [NEXT])
UNION
SELECT *
, rn = @rowcount + ROW_NUMBER() OVER(ORDER BY [ORDER])
FROM #temp
WHERE [ORDER] <=
(SELECT [ORDER]
FROM #temp
WHERE ID = [NEXT])) AS A
ORDER BY rn;
结果:
这应该起作用:
样本数据:
IF OBJECT_ID('tempdb..#temp') IS NOT NULL
DROP TABLE #temp;
CREATE TABLE #temp(ID INT
, [NEXT] INT
, [ORDER] INT);
INSERT INTO #temp
VALUES
(1456
, 1679
, 1),
(1679
, 1679
, 2),
(1578
, 1679
, 3),
(9492
, 1679
, 4);
查询:
DECLARE @rowcount INT;
SELECT @rowcount = COUNT(1)
FROM #temp
WHERE [ORDER] >
(SELECT [ORDER]
FROM #temp
WHERE ID = [NEXT]);
SELECT ID
FROM
(SELECT *
, rn = ROW_NUMBER() OVER(ORDER BY [ORDER])
FROM #temp
WHERE [ORDER] >
(SELECT [ORDER]
FROM #temp
WHERE ID = [NEXT])
UNION
SELECT *
, rn = @rowcount + ROW_NUMBER() OVER(ORDER BY [ORDER])
FROM #temp
WHERE [ORDER] <=
(SELECT [ORDER]
FROM #temp
WHERE ID = [NEXT])) AS A
ORDER BY rn;
结果:
与Joel的答案类似,仅使用窗口函数而不是内部联接或交叉应用:
SELECT
*
FROM
#temp t
ORDER BY
CASE
WHEN t.[Order] > MAX(CASE WHEN ID = [NEXT] THEN [ORDER] END) OVER () THEN -999999999 + t.[Order]
ELSE t.[Order]
END
这是一个使用交叉应用的版本
SELECT
t.*
FROM
#temp t
CROSS APPLY (SELECT [Order] FROM #temp WHERE ID = NEXT) n
ORDER BY
CASE
WHEN t.[Order] > n.[Order] THEN -99999999 + t.[Order]
ELSE t.[Order]
END
与Joel的答案类似,仅使用窗口函数而不是内部联接或交叉应用:
SELECT
*
FROM
#temp t
ORDER BY
CASE
WHEN t.[Order] > MAX(CASE WHEN ID = [NEXT] THEN [ORDER] END) OVER () THEN -999999999 + t.[Order]
ELSE t.[Order]
END
这是一个使用交叉应用的版本
SELECT
t.*
FROM
#temp t
CROSS APPLY (SELECT [Order] FROM #temp WHERE ID = NEXT) n
ORDER BY
CASE
WHEN t.[Order] > n.[Order] THEN -99999999 + t.[Order]
ELSE t.[Order]
END
另外,请标记您正在使用的相关数据库,如SQLServer、oracle、mysql、postgres。如果下一个是最高顺序,例如9492,该怎么办?按表中的顺序返回订单?@Matt没错!另外,请标记您正在使用的相关数据库,如SQLServer、oracle、mysql、postgres。如果下一个是最高顺序,例如9492,该怎么办?按表中的顺序返回订单?@Matt没错!我喜欢APPLY,但是由于内部查询的结果对于每一行都应该是一致的,因此我认为在这种情况下,内部连接是更好的选择。不过,加上一个窗口功能。这可能是最好的总体选择。它可能更快,并且您包含了将结果完全按ORDER BY子句排序的代码。@JoelCoehoorn我不确定我是否明白为什么您觉得交叉应用不会在每个实例中产生与您相同的结果?本例中的交叉应用程序基本上与内部连接完全相同,因为您是在1=1上连接的,并且我没有将任何值从表传递到应用程序中,因此它完全包含在order by中,就像您的一样。最上面的一个是带有条件聚合的窗口函数,因此不需要使用该函数进行apply或inner连接。是的,它将返回相同的结果。我对查询优化器识别apply运算符中的语句没有使用外部查询中的任何数据的能力缺乏信心,尽管我承认我实际上没有看过执行计划。@JoelCoehoorn是的,我也没有看过,我想看看。我会特别好奇window函数的执行计划与其他函数的执行计划,也许我会在我喜欢应用的某个点上进行检查,但是由于内部查询的结果对于每一行都应该是一致的,我认为在这种情况下,内部连接是更好的选择。不过,加上一个窗口功能。这可能是最好的总体选择。它可能更快,并且您包含了将结果完全按ORDER BY子句排序的代码。@JoelCoehoorn我不确定我是否明白为什么您觉得交叉应用不会在每个实例中产生与您相同的结果?本例中的交叉应用程序基本上与内部连接完全相同,因为您是在1=1上连接的,并且我没有将任何值从表传递到应用程序中,因此它完全包含在order by中,就像您的一样。最上面的一个是带有条件聚合的窗口函数,因此不需要使用该函数进行apply或inner连接。是的,它将返回相同的结果。我对查询优化器识别apply运算符中的语句没有使用外部查询中的任何数据的能力缺乏信心,尽管我承认我实际上没有看过执行计划。@JoelCoehoorn是的,我也没有看过,我想看看。我会特别好奇窗口函数的执行计划与其他函数的执行计划,也许我会在某个时候抽空检查一下