我需要拆分以逗号分隔的字符串,对其进行操作,然后将其连接回单个字符串,保留数据的原始顺序(如果可能)。
例如,采用这样的CREATE TABLE
语句(作为字符串)的列定义列表'BrentOzarColumn INTEGER, PaulWhiteColumn DATETIME, ErikDarlingColumn VARCHAR(100)'
。我想将逗号分隔的列表拆分为一个结果集,例如使用 SQL Server 的内置函数,如下所示STRING_SPLIT()
:SELECT TRIM([Value]) AS CoolDataPeople FROM STRING_SPLIT('BrentOzarColumn INTEGER, PaulWhiteColumn DATETIME, ErikDarlingColumn VARCHAR(100)', ',')
在不指定ORDER BY
子句的情况下,这会重复产生(通过巧合?)以下结果,这些结果似乎按照与字符串中相同的顺序进行排序:
一旦我得到了上面的结果集,我想对每一行应用一些额外的字符串操作(比如附加一些常量文本),然后用一个函数连接每一行,比如STRING_AGG()
(再见天数STUFF ... FOR XML PATH
:),顺序与原始字符串。所以我的最终结果的一个例子可能是'BrentOzarColumn INTEGER SQLROX, PaulWhiteColumn DATETIME SQLROX, ErikDarlingColumn VARCHAR(100) SQLROX'
.
最终我的问题是:函数的结果是否STRING_SPLIT()
以确定的顺序返回?我知道没有ORDER BY
子句,从 a Table
or之类的数据集中选择时不能保证排序View
,但想知道函数是否有区别?
当我输入这个时,我有一种预感,答案是否定的,排序不是确定性的,因此我不能保证结果的顺序。此外,我敢打赌,我在结果之上运行的每个函数都可能添加了额外的不确定性,尤其是当我将它们与STRING_AGG()
. (无论答案如何,我都感谢您的帮助,你们都是很酷的数据人。;)
不,它们不是按确定的顺序返回的。
虽然您不太可能看到它们以不同的顺序返回,但这并不能使当前行为具有确定性或可靠性。
ROW_NUMBER() OVER (ORDER BY (SELECT 1))
类似在 CTE 等中间位置应用到输出的技巧同样不能保证有效。STRING_SPLIT()
这是我在博客中提到的明显缺失的功能之一:Andy Mallon 也是如此:
在这里投票和评论:
(该项目特别要求返回一个额外的列来指示原始字符串中的位置,但由于向后兼容性问题,可能需要通过一个新函数来传递,类似于如何
CONCAT_WS
出现。)顺便说一句,文档最初指出:
在此提交中故意更改了这一点,以消除任何承诺退货订单的概念。现在文档指出:
为什么他们需要取消这个承诺?
我不熟悉内部实现,但我相信文档的原始版本是由观察者编写的,而不是函数作者。该语句可能是这样写的,因为这是他们在使用该函数时观察到的行为。当我们告诉人们从聚簇表中选择行时我们不需要
ORDER BY
时,我们中的许多人都会做同样的事情:“它们总是按这个顺序出来的。” 非常可靠,直到优化器选择不同的索引。我的猜测是他们正在为未来的行为掩盖他们的屁股。想想他们对函数工作方式所做的所有更改,以及对优化器的持续更改。
目前,使用简单的案例:
除了顺序之外,没有太多机会或理由。但是,当您
OUTER APPLY
针对nvarchar(max)
两个巨大的分区表之间的列,并且数据开始以批处理模式和/或并行处理时呢?他们是否必须在代码中编写额外的逻辑以确保所有输出以正确的顺序返回?值得吗?他们是否必须为将来的每个功能处理/优化器更改重新访问它以保持该承诺?他们正在做出哪些改变?
该文档最近已更新,以显示函数的新参数
enable_ordinal
,可在 Azure SQL 数据库中使用,并且即将在 SQL Server 2022 中推出:需要明确的是,添加此参数只会
ordinal
在输出中添加一列,指示value
原始字符串中的序列;它仍然不能保证输出将按列排序ordinal
。为此,您仍然需要添加ORDER BY
到输出中。