sp_executesql没有声明变量

时间:2018-05-16 20:57:24

标签: sql sql-server sp-executesql

我正在尝试做一些像这样的动态SQL,以便创建一个只显示更改的审核日志。

当我跑步时,我收到错误说明

  

必须声明标量变量“@OldValueOut”。

我以为我确实通过第二个参数声明了sp_executesql调用。

ALTER TRIGGER [dbo].[Lab_SubSpace_Contact_Changed] 
   ON [dbo].[Lab_SubSpace_Contact]
   AFTER INSERT,DELETE,UPDATE
AS 
BEGIN
    SET NOCOUNT ON;

    DECLARE @sql VARCHAR(4000),
            @sqlDeleted VARCHAR(4000),
            @sqlInserted NVARCHAR(4000),
            @columns NVARCHAR(4000),
            @item VARCHAR(80),
            @pos INT,
            @oldValue VARCHAR(100),
            @newValue VARCHAR(100),
            @tableName VARCHAR(80),
            @pkName VARCHAR(80);

    SET @tableName = 'Lab_SubSpace_Contact';
    SET @pkName = 'SubSpace_Id';

    SELECT * INTO #deleted FROM deleted;
    SELECT * INTO #inserted from inserted;

    SET @columns = STUFF((SELECT ',' + name
                          FROM sys.columns
                          WHERE object_id = OBJECT_ID(@tableName)
                            AND SUBSTRING(COLUMNS_UPDATED(), ((column_id - 1) / 8 + 1), 1) & (POWER(2, ((column_id - 1) % 8 + 1) - 1)) = POWER(2, (column_id - 1) % 8)
                          FOR XML PATH('')
                         ), 1, 1, '');

    WHILE LEN(@columns) > 0
    BEGIN
        SET @pos = CHARINDEX(',', @columns);
        IF @pos = 0
        BEGIN
            SET @item = @columns
        END;
        ELSE
        BEGIN
            SET @item = SUBSTRING(@columns, 1, @pos - 1);
        END;

        SET @sqlDeleted = N'SELECT @OldValueOut = ' + QUOTENAME(@item) + 'FROM #deleted WHERE ' + QUOTENAME(@pkName) + ' = ' + CONVERT(VARCHAR(100), @pkName);
        print @sqlDeleted;
        EXECUTE sp_executesql @sqlDeleted, N'@OldValueOut NVARCHAR(100) OUTPUT', @OldValueOut = @oldValue OUTPUT;

        SET @sqlInserted = N'SELECT @NewValueOut = ' + @item + ' FROM inserted WHERE ' + QUOTENAME(@pkName) + ' = ' + CONVERT(VARCHAR(100), @pkName);
        EXECUTE sp_executesql @sqlDeleted, N'@NewValueOut NVARCHAR(100) OUTPUT', @NewValueOut = @newValue OUTPUT;

        IF (LTRIM(RTRIM(@newValue)) != LTRIM(RTRIM(@oldValue)))
        BEGIN
            SET @sql = 'INSERT INTO [dbo].[Audit_Log] (Table_Name, Primary_Key, Column_Name, Old_Value, New_Value, Modified, Updated_By_WWID) VALUES (' +
                        QUOTENAME(@tableName, '''') + ',' +
                        QUOTENAME(@pkName, '''') + ',' + 
                        QUOTENAME(@item, '''') + ',' +
                        QUOTENAME(@oldValue, '''') + ',' +
                        QUOTENAME(@newValue, '''') + ',' +
                        GETDATE() + ',' +
                        '1234' + ')';
            EXEC(@sql);
        END;

        SET @item = '';
        SET @newValue = '';
        SET @oldValue = ''

        IF @pos = 0 
        BEGIN
            SET @columns = '';
        END;
        ELSE
        BEGIN
            SET @columns = SUBSTRING(@columns, @pos + 1, LEN(@columns) - @pos);
        END;
    END ;

    DROP TABLE #inserted;
    DROP TABLE #deleted;
END

2 个答案:

答案 0 :(得分:1)

我永远不会记得使用sp_executesql为变量订购声明的正确方法。所以,我只是作弊并使用相同的变量名称:

DECLARE @oldValueOut VARCHAR(100);

    SET @sqlDeleted = N'
SELECT @OldValueOut = ' + QUOTENAME(@item) + '
FROM #deleted 
WHERE ' + QUOTENAME(@pkName) + ' = ' + CONVERT(VARCHAR(100), @pkName);

EXECUTE sp_executesql @sqlDeleted, 
                      N'@OldValueOut NVARCHAR(100) OUTPUT',
                      @OldValueOut = @oldValueOut OUTPUT;

Here是一个简化版本,表明这适用于@oldValueOut

答案 1 :(得分:0)

糟糕。我的第二个sp_execute也引用旧值而不是新值。谢谢大家。