我使用SQL查询信息已有一段时间了,但是我对创建触发器是陌生的。我和一位同事已经意识到,我们的本地数据没有审核记录,因此,我正在尝试学习纠正此问题。不用担心,这只是背景知识-我并不是在这里寻求指导(尽管任何链接都会有所帮助……令人惊讶的是,我读过的文章很少能真正解释其任何代码的含义)。这是在SQL Server 2012上。
因此,我想我已经准备好开始测试它的代码,但是问题是Incorrect syntax near ','
每次触发触发器时,我都会在第7行得到一个代码。供参考,这里是触发器:
-- =============================================
-- Author: L. LeBlanc
-- Create date: 8/6/2015
-- Description: Testing auditing functionality
-- =============================================
ALTER TRIGGER [dbo].[testAuditTrigger]
ON [SalesForce].[dbo].[DistinctTest]
FOR INSERT, UPDATE, DELETE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
declare @id uniqueidentifier,
@changedate varchar(21),
@op nvarchar(50),
@cols nvarchar(max),
@rc bigint,
@user varchar(128),
@act int,
@bitcols int,
@bit int,
@field int,
@char INT,
@maxfield int,
@fieldname varchar(128),
@sql varchar(2000),
@PKCols VARCHAR(1000),
@PKSelect VARCHAR(1000),
@auditcols int
select @user = system_user,
@changedate = convert(varchar(8), getdate(), 112) + ' ' + convert(varchar(12), getdate(), 114)
-- determine action
if exists (select * from inserted)
begin
if exists (select * from deleted)
set @act = '0' -- update
else
set @act = '1' -- insert
end
else
set @act = '2' -- delete
-- get list of columns
SELECT * INTO #ins FROM inserted
SELECT * INTO #del FROM deleted
-- Get primary key columns for full outer join
SELECT @PKCols = COALESCE(@PKCols + ' and', ' on')
+ ' i.' + c.COLUMN_NAME + ' = d.' + c.COLUMN_NAME
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
WHERE pk.TABLE_NAME = 'DistinctTest'
AND CONSTRAINT_TYPE = 'PRIMARY KEY'
AND c.TABLE_NAME = pk.TABLE_NAME
AND c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
-- Get primary key select for insert
SELECT @PKSelect = COALESCE(@PKSelect+'+','')
+ '''<' + COLUMN_NAME
+ '=''+convert(varchar(100),
coalesce(i.' + COLUMN_NAME +',d.' + COLUMN_NAME + '))+''>'''
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS pk ,
INFORMATION_SCHEMA.KEY_COLUMN_USAGE c
WHERE pk.TABLE_NAME = 'DistinctTest'
AND CONSTRAINT_TYPE = 'PRIMARY KEY'
AND c.TABLE_NAME = pk.TABLE_NAME
AND c.CONSTRAINT_NAME = pk.CONSTRAINT_NAME
if @act = '0'
begin -- convert ye olde binarye to text
set @bitcols = COLUMNS_UPDATED()
SELECT TABLE_NAME, COLUMN_NAME,
COLUMNPROPERTY(OBJECT_ID(TABLE_SCHEMA + '.' + TABLE_NAME),
COLUMN_NAME, 'ColumnID') AS COLUMN_ID
FROM SalesForce.INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'DistinctTest';
end
else
set @cols = ''
select @auditcols = count(*)
from SalesForce.INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'DistinctTest_Audit'
SELECT @field = 0,
@maxfield = MAX(ORDINAL_POSITION)
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'DistinctTest'
WHILE @field < @maxfield
BEGIN
SELECT @field = MIN(ORDINAL_POSITION)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'DistinctTest'
AND ORDINAL_POSITION > @field
SELECT @bit = (@field - 1 )% @auditcols + 1
SELECT @bit = POWER(2,@bit - 1)
SELECT @char = ((@field - 1) / @auditcols) + 1
IF SUBSTRING(COLUMNS_UPDATED(),@char, 1) & @bit > 0
OR @act IN ('1','2') -- insert or delete
BEGIN
SELECT @fieldname = COLUMN_NAME
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = 'DistinctTest'
AND ORDINAL_POSITION = @field
SELECT @sql = CONCAT('
insert DistinctTest.Audit ( Id,
Operation,
ColumnsModified,
ChangeDate,
ChangeUser)
select ''', @id , ''','''
, @op , ''',' , @cols
, ',''' , @changedate , ''''
, ',''' , @user , ''''
, ' from #ins i full outer join #del d'
, @PKCols
, ' where i.' , @fieldname , ' <> d.' , @fieldname
, ' or (i.' , @fieldname , ' is null and d.'
, @fieldname
, ' is not null)'
, ' or (i.' + @fieldname + ' is not null and d.'
, @fieldname
, ' is null)' )
EXEC (@sql)
END
END
END
当我sp_helptext
在触发器上使用时,它会为我提供与触发器开始时相同的结果。我已经看了几个例子,并且在努力弄清楚到底是什么使我的触发器在这种特殊情况下与众不同。ON [SalesForce].[dbo].[DistinctTest]
据我所知,第7行是根据编译器编写的。
我也承认我对SQL编译器的工作原理不了解,所以我不知道“第7行”是否实际上是用词不当,并且错误与代码主体中的某些逻辑有关。但是,根据我所阅读的内容,sp_helptext
可以准确地打印出编译器实际正在读取的脚本。我希望不必因为这个特定错误而经历整个触发器,因为它看起来很简单。
但是,简单性也是令我感到困扰的-在第7行附近,我看不到任何多余的逗号,并且此触发器的声明与我在其他地方看到的大多数声明几乎相同。我还做过一些测试触发器,这些触发器以前工作都很好,但是它们只对一种DML操作而不是对三种触发。
由于触发器具有动态sql且未在包含在动态sql中之前未设置变量中的至少一个,因此引发了错误。这将以无效的sql语句结束。如果要查看动态sql,可以在执行它之前添加一条print或select语句以输出@SQL的内容。您将不得不使用SSMS进行查看,但这将有助于调试。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句