使用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的恶作剧。
答案 0 :(得分:1)
+ =运算符仅适用于SQL Server中的数字数据类型。 Microsoft documentation here
对于字符串串联,您需要分别编写赋值和串联。
DECLARE @sql nvarchar(max);
SELECT @sql = N'';
SELECT @sql = @sql + [definition] + N'
GO
'
FROM sys.sql_modules
WHERE OBJECT_NAME(object_id) LIKE 'dt%'
ORDER BY OBJECT_NAME(object_id);
PRINT @sql;
此外,如果您正在Management Studio中运行此查询,请记住,它将返回的数据大小(包括在print语句中)受到限制。因此,如果模块的定义超出此限制,则它们将在输出中被截断。
答案 1 :(得分:0)
它按预期工作:
DECLARE @sql nvarchar(max);
SELECT @sql =COALESCE(@sql + N' GO ','')+[definition]
FROM sys.sql_modules
Print @sql;
答案 2 :(得分:0)
我很确定PRINT命令是造成麻烦的原因。
当我尝试:
DECLARE @SQL NVARCHAR(MAX) = N'';
SELECT @sql += SUBSTRING( [definition], 1, 100 ) + CHAR(13) + CHAR(10) + 'GO' + CHAR(13) + CHAR(10)
FROM SYS.SQL_MODULES
PRINT @sql;
我得到了所有程序(前100个字符...)。因此,这似乎是PRINT命令的限制。
第二次尝试,另一个没有“子字符串”的数据库:
DECLARE @SQL NVARCHAR(MAX) = N'';
SELECT @sql += [definition] + CHAR(13) + CHAR(10) + 'GO' + CHAR(13) + CHAR(10)
FROM SYS.SQL_MODULES
PRINT @sql;
现在我得到了1,5个程序:第一个完成,第二个停止在proc的联机中间。 PRINT中有一个限制
第三次尝试,以证明我的假设:
DECLARE @SQL NVARCHAR(MAX) = N'';
SELECT @sql += [definition] + 'GO' FROM SYS.SQL_MODULES
PRINT @sql;
现在我又获得了一行代码!所以对我来说,这就是PRINT在某种程度上有局限性的证明。
最后一次尝试:
DECLARE @SQL NVARCHAR(MAX) = N'';
SELECT @sql += [definition] + N'GO' FROM SYS.SQL_MODULES
PRINT SUBSTRING(@SQL,1,4000)
PRINT SUBSTRING(@SQL,4001,4000)
结果:现在我得到了2个以上的过程,尽管4K之后出现了换行符,但是这可能发生在...不好的地方。
答案 3 :(得分:0)
以下代码演示了从一组有序行中获取列值,并使用def makePDF(path, filename, image_files):
output_file = path + '/' + filename + ".pdf"
try:
with open(output_file,"wb") as f:
f.write(img2pdf.convert(image_files))
#f.close()
except IOError as error:
print ('opss')
pass
创建了一个聚合字符串,这些字符串之间有分隔符,包括换行符。
for xml
答案 4 :(得分:0)
要添加到@HABO的注释中,未定义聚合字符串串联的行为,并且结果取决于计划。使用FOR XML提供确定性结果并遵守ORDER BY
子句:
DECLARE @sql nvarchar(max);
SET @sql =
(SELECT [definition] + N'
GO
'
FROM sys.sql_modules
WHERE OBJECT_NAME(object_id) LIKE 'dt%'
ORDER BY OBJECT_NAME(object_id)
FOR XML PATH(''), TYPE).value('(./text())[1]', 'nvarchar(MAX)');
PRINT @sql; --SSMS will truncate long strings