【发布时间】:2018-07-12 23:44:31
【问题描述】:
使用 SQL Server 2012,我发现尝试基于表中的 nvarchar(max) 列构建字符串似乎无法正常工作。它似乎覆盖,而不是附加。任意示例:
DECLARE @sql nvarchar(max);
SELECT @sql = N'';
SELECT @sql += [definition] + N'
GO
'
FROM sys.sql_modules
WHERE OBJECT_NAME(object_id) LIKE 'dt%'
ORDER BY OBJECT_NAME(object_id);
PRINT @sql;
这应该打印出数据库中所有各种 dt_ 表的所有 SQL 模块定义,由 GO 分隔,作为可以运行的脚本。但是...这仅打印出 LAST 模块定义,而不是所有模块的总和。它的行为就好像“+=”只是一个“=”。
如果您稍微更改它...例如将 [definition] 转换为 nvarchar(4000),它会突然按预期工作。此外,如果您选择任何其他非 nvarchar(max) 或 varchar(max) 类型的列,它会按预期工作。示例:
DECLARE @sql nvarchar(max);
SELECT @sql = N'';
SELECT @sql += CAST([definition] AS nvarchar(4000)) + '
GO
'
FROM sys.sql_modules
WHERE OBJECT_NAME(object_id) LIKE 'dt%'
ORDER BY OBJECT_NAME(object_id);
PRINT @sql;
这是一个已知的错误吗?或者这是否按预期工作?难道我做错了什么?有什么办法可以让我正常工作吗?我尝试了十几种不同的方法,包括确保连接中的每个表达式都是相同的 nvarchar(max) 类型,包括字符串文字。
注意:这个例子只是一个说明问题的例子,而不是我在现实生活中想要做的。如果您的数据库没有定义“dt*”表,您可以更改 WHERE 子句以指定您想要的任何数据库中的任何表组或存储过程,您将得到相同的结果......只有最后一个出现在@sql 字符串中,就好像您只是使用“=”而不是“+=”。此外,明确声明“@sql = @sql +”的行为方式相同...适用于除 nvarchar(max) 或 varchar(max) 之外的所有字符串类型。
我已经验证了 [definition] 值都不是 NULL,因此没有 NULL 恶作剧发生。
【问题讨论】:
-
旁白:如here 所述,使用
for xml连接值是可靠的。 -
添加到@HABO 的评论中,聚合字符串连接的行为是未定义的,结果取决于计划。您必须在更高版本的 SQL Server 中使用 XML PATH 方法或 STRING_AGG()。
-
在 SSMS 之外尝试这个,像 LinqPad 或任何其他外部工具一样尝试
-
不推荐这样做。来自
SET @local_variable:“不要在 SELECT 语句中使用变量来连接值(即计算聚合值)。可能会出现意外的查询结果。这是因为 SELECT 列表中的所有表达式(包括赋值)都不能保证每个输出行只执行一次" -
有趣...当我使用普通字符串类型时,它对我来说总是可靠地工作,从 2005 年到 2017 年的每个 SQL Server 版本。我只遇到过 varchar(最大)类型。
标签: sql-server tsql sql-server-2012