Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/jenkins/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 串联nvarchar(max)值不';似乎不起作用_Sql Server_Tsql_Sql Server 2012 - Fatal编程技术网

Sql server 串联nvarchar(max)值不';似乎不起作用

Sql server 串联nvarchar(max)值不';似乎不起作用,sql-server,tsql,sql-server-2012,Sql Server,Tsql,Sql Server 2012,使用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%' ORDE

使用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_uu表的所有SQL模块定义,以GO分隔,作为一个脚本,然后可以运行。然而。。。这只打印最后一个模块定义,而不是所有模块定义的总和。它的行为就像“+=”只是一个“=”一样

如果你稍微改变一下。。。将[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;
这是已知的bug吗?或者这是否如预期的那样起作用?我做错什么了吗?我有没有办法让它正常工作?我尝试了十几种不同的方法,包括确保串联中的每个表达式都是相同的nvarchar(max)类型,包括字符串文本

注意:这个例子只是一个说明问题的例子,而不是我在现实生活中想要做的。如果您的数据库没有定义“dt*”表,您可以更改WHERE子句以指定所需数据库中的任何一组表或存储过程,您将得到相同的结果。。。只有最后一个出现在@sql字符串中,就好像您只是执行了“=”而不是“+=”一样。另外,显式声明“@sql=@sql+”的行为方式与。。。除nvarchar(最大值)或varchar(最大值)外,所有字符串类型均可正常工作

我已经验证了[definition]值中没有一个也是空的,因此没有出现空的诡计。

它按预期工作:

DECLARE @sql nvarchar(max);
SELECT @sql =COALESCE(@sql + N' GO ','')+[definition]
FROM sys.sql_modules 


Print @sql;

+=运算符仅适用于SQL Server中的数字数据类型

对于字符串连接,需要分别编写赋值和连接

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;

此外,如果您在ManagementStudio中运行此查询,请记住它将返回的数据大小(包括在打印语句中)有一个限制。因此,如果模块的定义超过此限制,它们将在输出中被截断。

我很确定打印命令是出现问题的原因

当我尝试时:

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命令的限制

第二次尝试,另一个数据库,没有“子字符串”:

现在我得到1,5个程序:第一个完成,第二个在中间的中间停止。印刷品是有限度的

第三,证明我的假设:

DECLARE @SQL NVARCHAR(MAX) = N'';
SELECT @sql += [definition] + 'GO' FROM SYS.SQL_MODULES 
PRINT @sql;
现在我又得到了一行代码!所以对我来说,这就是证据,印刷品在某种程度上是有限制的

最后一次尝试:

DECLARE @SQL NVARCHAR(MAX) = N'';
SELECT @sql += [definition] + N'GO' FROM SYS.SQL_MODULES 
PRINT SUBSTRING(@SQL,1,4000)
PRINT SUBSTRING(@SQL,4001,4000)

结果:现在我得到了两个以上的程序,虽然现在4K后有一个断线,但这可能发生在。。。错误位置。

以下代码演示如何从一组有序行中获取列值,并使用
for xml
,在值之间创建带分隔符(包括换行符)的聚合字符串

-- Carriage return and linefeed characters.
declare @CRLF as NVarChar(16) = NChar( 13 ) + NChar( 10 );
-- Carriage return and linefeed characters XML encoded.
declare @EncodedCRLF as NVarChar(16) = N'
';
-- Separator to insert between source rows in the accumulated string.
declare @Separator as NVarChar(64) = ';' + @EncodedCRLF + 'go;' + @EncodedCRLF + 'do something with ';
-- Characters in   @Separator   to remove from the first element in   @Result .
declare @SkipCount as Int = 4 + 2 * Len( @EncodedCRLF );
-- The result.
declare @Result as NVarChar( max ) = '';

-- Do it.
select @Result =
  Replace(
    Stuff(
      -- Specify the sorting order of the XML elements in the following   select   statement.
      ( select @Separator + name from sys.tables order by name desc for XML path(''), type).value('.[1]', 'VarChar(max)' ),
      1, @SkipCount, '' ),
    @EncodedCRLF, @CRLF );

-- Output the result.
select @Result as [Result];
-- Output the result with line breaks shown.
print @Result; -- Switch to   Messages   tab in SSMS to see result.

要添加到@HABO的注释中,聚合字符串连接的行为是未定义的,结果取决于计划。使用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

旁白:如前所述,使用xml的
连接值是可靠的。要添加到@HABO的注释中,聚合字符串连接的行为是未定义的,结果取决于计划。您必须在更高版本的SQL Server中使用XML PATH方法或字符串_AGG()。请在SSMS之外尝试此方法,如在LinqPad或任何其他外部工具中尝试此方法。不推荐这样做。From:“不要在SELECT语句中使用变量来连接值(即,计算聚合值)。可能会出现意外的查询结果。这是因为SELECT列表中的所有表达式(包括赋值)不能保证对每个输出行执行一次…”。。。当我使用普通字符串类型时,它对我来说总是可靠的,从2005年到2017年,在SQL Server的每个版本上都是如此。我只在使用varchar(max)类型时遇到过这个问题。+=不仅仅用于数字数据类型。在你在页面底部错过的链接中,还有另一个字符串concat的链接。这实际上可能只是select语句中+=字符串串联操作的一个奇怪之处。看起来SQL Server可能只处理一次分配。但正如我在问题中所说,将其更改为“@SQL=@SQL+”并不能修复或更改它。而“+=”也适用于所有其他字符串类型。。。只是不是varchar(最大值)或nvarchar(最大值)。如果您使用varchar(max)列创建自己的表,并在其中放入短字符串,则会得到相同的行为。这显然不是一个“数据量”问题。我真的不认为这是问题。我还使用WHILE循环一次只打印一行。它只得到最后一个,不是所有的。我认为在您的示例中,子字符串将值转换为nvarchar(100)或其他值,因此它“起作用”。如果你把它留在varchar(max),它就不会。您可以使用varchar(max)创建自己的表,只需在其中放入短字符串即可进行复制。+=连接似乎不适用于varchar(max)列。@pmbAustin:也许你的“转换”想法与此有关。我编辑了这个问题以在另一个数据库上测试它。结果是:1得到了1,5个程序:第一个正常,第二个坏了(停在中间)不,我得到了完全相同的行为。。。在选择之后,@sql变量只包含最后一行的[definition]。。。并非如预期的那样,将返回的所有行的所有定义串联在一起。这是因为ORDER BY。我复制/粘贴了您的原始代码,它在我的s上按预期工作
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