将没有列的 ROW_NUMBER() 添加到 ORDER BY?

Bra*_*adC 7 sql-server order-by window-functions sql-server-2017

所以我正在研究一个代码高尔夫拼图,需要在保持当前顺序的同时向结果添加一个 INT“数字”列n

假设我的源数据是:

SELECT value
FROM STRING_SPLIT('one,two,three,four,five', ',')
Run Code Online (Sandbox Code Playgroud)

它以原始(所需)顺序返回项目:

value
-----
one
two
three
four
five
Run Code Online (Sandbox Code Playgroud)

如果我尝试使用ROW_NUMBER()RANK()我被迫指定一个ORDER BY,这value是唯一合法的选择:

SELECT value, n = ROW_NUMBER() OVER(ORDER BY value)
FROM STRING_SPLIT('one,two,three,four,five',',')
Run Code Online (Sandbox Code Playgroud)

但这(如预期)按value字母顺序排序,而不是按所需的原始顺序排列:

value   n
------ ---
five    1
four    2
one     3
three   4
two     5
Run Code Online (Sandbox Code Playgroud)

连接到数字表不起作用,因为如果没有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
Run Code Online (Sandbox Code Playgroud)

但这真的很长很烦人。有什么更好的想法吗?

Joe*_*ish 10

该规范的方式做到这一点是: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',',')
Run Code Online (Sandbox Code Playgroud)

它适用于您在问题中发布的简单案例:

在此处输入图片说明

我应该说,没有文件保证该ROW_NUMBER()值将按照您期望的精确顺序排列。但它是代码高尔夫,所以这似乎已经足够了。


Aar*_*and 6

您不能依赖于按照原始字符串的顺序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;
Run Code Online (Sandbox Code Playgroud)

对于代码高尔夫也许:

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
Run Code Online (Sandbox Code Playgroud)

如果您有重复项,它会变得更加复杂。这里可能有一些想法:


Pau*_*ite 5

另一种选择是使用序列:

DROP SEQUENCE IF EXISTS dbo.S;
CREATE SEQUENCE dbo.S START WITH 1;

SELECT value, NEXT VALUE FOR dbo.S 
FROM STRING_SPLIT('one,two,three,four,five', ',');
Run Code Online (Sandbox Code Playgroud)

输出:

?????????????
? one   ? 1 ?
? two   ? 2 ?
? three ? 3 ?
? four  ? 4 ?
? five  ? 5 ?
?????????????
Run Code Online (Sandbox Code Playgroud)

STRING_SPLIT在没有内置编号选项的情况下实现是很烦人的。在https://feedback.azure.com/forums/908035-sql-server/suggestions/32902852-string-split-is-not-feature-complete投票支持更改