我正在尝试做一些像这样的动态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
答案 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也引用旧值而不是新值。谢谢大家。