首页 > 解决方案 > TSQL:在 INSERT 之后运行 exec

问题描述

我需要从多个表中转换旧数据。我现在才发现,在为一个表编写存储过程之后,它还需要处理来自其他几个表的数据。这意味着需要更改我的程序以正确处理此问题。我想动态地做到这一点,同时远离性能影响。我了解了如何使用 exec sp_executesql @SQLStatement 来避免动态 SQL 的性能问题。

但是,如果我写以下内容,我不会得到任何结果:

SET @SQLStatement = 'select CONVERT(XML, ' + @ConvColumn + ') ' + @AdditionalColumns + ' from ' + @ConvTable
INSERT INTO @TempDataConv
exec sp_executesql @SQLStatement

然而,如果我写它明确定义表和列,这工作得很好:

INSERT INTO @TempDataConv
SELECT
    DecPageID,
    PolicyID,
    PolicyNumber,
    CONVERT(XML, DecInfo),
    null
FROM [InternalPortal].[dbo].Decpages

可能会发生什么?由于没有返回任何结果,我不确定如何找出问题所在。我认为也许我无法做到以下几点。真的吗?我应该简单地将其写在不同表的 if 块中吗?

 INSERT INTO @TempDataConv
exec sp_executesql @SQLStatement

标签: sqlsql-servertsqlsql-server-2016

解决方案


我怀疑如果您执行INSERT内部动态语句,而不是使用INSERT INTO...EXEC.... 这将导致这样的事情:

DECLARE @ConvColumn sysname,
        @CRLF nchar(2) = NCHAR(13) + NCHAR(10);
DECLARE @AdditionalColumns table (Position int,ColumnName sysname);

SET @ConvColumn = N'DecInfo';

INSERT INTO @AdditionalColumns
VALUES(1,N'DecPageID'),
      (2,N'PolicyID'),
      (3,N'PolicyNumber');

DECLARE @SQL nvarchar(MAX);

SET @SQL = N'INSERT INTO dbo.YourTable ({ColumnsList})' + @CRLF +
           N'SELECT CONVERT(xml, ' + QUOTENAME(@ConvColumn) + N'),' + @CRLF +
           STUFF((SELECT N',' + @CRLF +
                         N'       ' + QUOTENAME(ColumnName)
                  FROM @AdditionalColumns
                  ORDER BY Position ASC
                  FOR XML PATH(N''),TYPE).value('.','nvarchar(MAX)'),1,3,N'') + @CRLF +
          N'FROM [InternalPortal].[dbo].Decpages;';

--PRINT @SQL; --Your debugging best friend

EXEC sys.sp_executesql @SQL;

需要注意的是,您将无法使用表变量INSERT进入,但是,您可以在动态语句的范围之外创建一个临时表并INSERT进入该表。

另请注意,我通过使用QUOTENAME. 这就是为什么我使用表变量来存储列名的原因,因为你永远无法使用分隔列表来实现这一点(这真的会让注入门大开)。您还需要替换{ColumnsList}为要插入的实际列。


推荐阅读