为什么串联顺序会随着用户定义的表类型而改变?

Int*_*ble 3 sql-server concat sql-server-2014

在使用CONCAT用户定义的表类型时,我遇到了在我看来是一个奇怪的排序问题。

我已经把 SQL 放在下面,让我可以重现这个:

我有以下用户类型:

CREATE TYPE [dbo].[StringList] AS TABLE
(
    [Value] VARCHAR(8000) NOT NULL
)
Run Code Online (Sandbox Code Playgroud)

以及以下用于设置所有内容的查询:

DECLARE @ColumnNames AS TABLE([ColumnName] VARCHAR(MAX))
DECLARE @ValueTable AS [dbo].[StringList] --VariableLineA
--DECLARE @ValueTable AS TABLE([Value] VARCHAR(MAX)) --VariableLineB

INSERT INTO @ColumnNames([ColumnName])
VALUES
('Forename'),
('Surname')

INSERT INTO @ValueTable([Value])
VALUES
('Ellis'), ('Ali')
Run Code Online (Sandbox Code Playgroud)

这是我正在运行的查询:

SELECT CONCAT(STRING_AGG(CONCAT([ColumnName], ' - ',  [sc].[Value]), ', '), ', ') -- QueryLineA
        --CONCAT(STRING_AGG([ColumnName] + ' - ' + [sc].[Value], ', '), ', ') --QueryLineB
FROM        @ValueTable AS [sc]
INNER JOIN  @ColumnNames ON 1=1
Run Code Online (Sandbox Code Playgroud)

如果该VariableLineB行被取消注释,并且该VariableLineA行被注释掉,那么如果单独或一起运行,将为两个查询行返回以下字符串:

Forename - Ellis, Forename - Ali, Surname - Ellis, Surname - Ali,

如果该VariableLineA行未注释且该VariableLineB行被注释掉,则为 返回以下字符串QueryLineB,如果一起运行,则从两个查询中返回以下字符串,但不是 单独运行QueryLineA

Forename - Ellis, Forename - Ali, Surname - Ellis, Surname - Ali,

单独QueryLineA运行时,将返回以下字符串:

Forename - Ellis, Surname - Ellis, Forename - Ali, Surname - Ali,

为什么顺序变了?我在这里看到了什么,有什么办法可以防止这种情况发生?

在使用方面, 的值@ValueTable将被传递到函数中,并且原始顺序(无论是什么)保持不变很重要。

Mar*_*ith 9

顺序发生变化是因为交叉联接中涉及的表的顺序发生了变化。在一个计划中@ValueTable是外部(驱动)表,在另一个计划中是@ColumnNames外部表。

for each row in @ColumnNames
    for each row in @ValueTable
    concatenate the result
    //produces Forename - Ellis, Forename - Ali, Surname - Ellis, Surname - Ali, 


for each row in @ValueTable
    for each row in @ColumnNames
    concatenate the result 
    //produces "Forename - Ellis, Surname - Ellis, Forename - Ali, Surname - Ali,"
Run Code Online (Sandbox Code Playgroud)

除非在查询中指定,否则永远不会保证顺序,因此如果一致的顺序很重要,您应该添加一个稳定的 order by 子句,为定义中的两个表定义顺序STRING_AGG

SELECT CONCAT(STRING_AGG(CONCAT([ColumnName], ' - ',  [sc].[Value]), ', ') 
                        WITHIN GROUP (ORDER BY [ColumnName],  [sc].[Value])  , ', ') -- QueryLineA
FROM        @ValueTable AS [sc]
INNER JOIN  @ColumnNames ON 1=1
Run Code Online (Sandbox Code Playgroud)

  • 是的,情况总是如此。[字符串拆分文档](https://docs.microsoft.com/en-us/sql/t-sql/functions/string-split-transact-sql?view=sql-server-ver15) 明确警告`输出行可以按任何顺序排列。顺序不能保证与输入字符串中子字符串的顺序相匹配,但不幸的是,它们在指示顺序的函数结果中没有提供任何替代输出列,因此这通常被忽略。 (3认同)