Sql-Server

將沒有列的 ROW_NUMBER() 添加到 ORDER BY?

  • November 1, 2018

所以我正在研究一個程式碼高爾夫拼圖,需要在結果中添加一個 INT“數字”列n,同時保持目前順序。

假設我的源數據是:

SELECT value
FROM STRING_SPLIT('one,two,three,four,five', ',')

它以原始(所需)順序返回項目:

value
-----
one
two
three
four
five

如果我嘗試使用ROW_NUMBER()或者RANK()我被迫指定一個ORDER BY,這value是唯一合法的選擇:

SELECT value, n = ROW_NUMBER() OVER(ORDER BY value)
FROM STRING_SPLIT('one,two,three,four,five',',')

但這(如預期的那樣)按value字母順序排序,而不是按所需的原始順序排列:

value   n
------ ---
five    1
four    2
one     3
three   4
two     5

加入數字表是行不通的,因為沒有WHERE子句我會得到一個完整的外連接。

我能想到的最好的方法是使用帶有標識欄位的臨時表:

CREATE TABLE #argg (n INT IDENTITY(1,1), v VARCHAR(99))

INSERT #argg 
SELECT value v
FROM STRING_SPLIT('one,two,three,four,five',',')

SELECT *
FROM #argg

DROP TABLE #argg

但這真的很長而且很煩人。有更好的想法嗎?

執行此操作的規範方法如下ROW_NUMBER() OVER(ORDER BY (SELECT NULL)):如果你在打高爾夫球,你可以嘗試這樣的事情:

SELECT value, n = ROW_NUMBER() OVER(ORDER BY (SELECT 1))
FROM STRING_SPLIT('one,two,three,four,five',',')

它適用於您在問題中發布的簡單案例:

在此處輸入圖像描述

我應該說,沒有文件保證該ROW_NUMBER()值將按照您期望的精確順序。但這是程式碼高爾夫,所以這似乎已經足夠好了。

您不能依賴您INSERT按原始字元串的順序生成IDENTITY值。這可能是你觀察到的,但這只是幸運的巧合,當然不能保證。

如果您沒有重複項,以下將起作用:

DECLARE @str varchar(255) = 'one,two,three,four,five';

SELECT value, n = ROW_NUMBER() OVER
 (ORDER BY CHARINDEX(',' + value + ',', ',' + @str + ','))
FROM STRING_SPLIT('one,two,three,four,five', ',')
ORDER BY n;

對於程式碼高爾夫也許:

DECLARE @s char(99)='one,two,three,four,five';
SELECT value,n=RANK() OVER(ORDER BY CHARINDEX(','+value+',',','+@s+','))
FROM STRING_SPLIT('one,two,three,four,five', ',')ORDER BY n

如果你有重複,它變得更加複雜。這裡的一些想法可能是:

引用自:https://dba.stackexchange.com/questions/221290