STRING_SPLIT 和有序结果

use*_*722 4 sql-server

你能假设 string_split 函数的结果按顺序返回元素吗?总之,下面的代码正确吗?

DECLARE @tags NVARCHAR(400) = 'clothing,road,touring,bike' 
DECLARE @FIRST nvarchar(100);

SELECT TOP 1 @FIRST = value 
FROM STRING_SPLIT(@tags, ',');  
Run Code Online (Sandbox Code Playgroud)

Aar*_*and 13

TOP 1没有ORDER BY不能保证返回即使输出相同的结果STRING_SPLIT()得到了保障(其中最绝的是不是)。虽然在实际使用中,您可能会发现很难提出数据未按顺序返回的反例,但这是一种可怕的做法。相信某样东西总是有效,因为你从未见过它坏掉,就像假设如果你在高速公路上放了一个鹿标志,那是你唯一能看到鹿的地方。

但是,让我们看看可以解决此问题的另一种方法。为什么我们不定位整个列表中每个单独字符串的位置:

DECLARE 
  @tags nvarchar(400) = N'clothing,road,touring,bike',
  @c nchar(1) = N',';

SELECT value, CHARINDEX(@c + value + @c, @c + @tags + @c) 
  -- we surround the value and the string with leading/trailing ,
  -- so that cloth isn't a false positive for clothing
  FROM STRING_SPLIT(@tags, ',') AS t;
Run Code Online (Sandbox Code Playgroud)

这里的输出是:

带字符索引的输出

你认为我们可以用它来确定列表中的第一个元素吗?当然!让我们再试一次:

DECLARE 
  @tags nvarchar(400) = N'clothing,road,touring,bike',
  @first nvarchar(100),
  @c nchar(1) = N',';

;WITH t AS
(
  SELECT value, idx = CHARINDEX(@c + value + @c, @c + @tags + @c) 
  FROM STRING_SPLIT(@tags, ',')
)
SELECT TOP (1) @first = value FROM t ORDER BY idx;

PRINT @first;
Run Code Online (Sandbox Code Playgroud)

输出:

clothing
Run Code Online (Sandbox Code Playgroud)

您可以使用相同的逻辑来查找最后一个元素,只需将 更改ORDER BY idxORDER BY idx DESC。实际上,您可以使用此逻辑返回列表中的第 n 个字符串:

DECLARE 
  @tags nvarchar(400) = N'clothing,road,touring,bike',
  @c nchar(1) = N',',
  @nth tinyint;

SET @nth = 3;

;WITH t AS
(
  SELECT value, idx = ROW_NUMBER() OVER 
    (ORDER BY CHARINDEX(@c + value + @c, @c + @tags + @c))
  FROM STRING_SPLIT(@tags, ',')
)
SELECT * FROM t WHERE idx = @nth;
Run Code Online (Sandbox Code Playgroud)

结果:

touring
Run Code Online (Sandbox Code Playgroud)

作为免责声明,如果您有重复项,那将会把事情搞砸,因为索引值将始终代表该值在字符串中的第一次出现。您可以从ROW_NUMBER()to切换,DENSE_RANK()但这不能解决所有情况。你可以先去重复字符串(我在这里谈论一些边缘情况)。


Bre*_*zar 10

SQL Server 的 STRING_SPLIT 文档没有指定顺序保证。

有一个公开的反馈请求向 STRING_SPLIT 添加更多功能,包括排序,但截至本答案(2018 年中),状态只是“正在审查”。

目前,如果您需要保证输出顺序,请尝试其他字符串拆分技术