我已经使用SQL来查询信息一段时间了,但我是创建触发器的新手。我和同事已经意识到我们的本地数据没有审计跟踪,因此我正在努力学习纠正这一点。不要担心,这只是背景 - 我不是在这里要求指南(虽然任何链接都会有所帮助......令人惊讶的是我读过的文章很少,实际上解释了他们的任何代码意味着什么)。这是在SQL Server 2012上。
所以,我认为我想要开始测试它的代码,但问题是每次触发器触发时我都会在第7行得到Incorrect syntax near ','
。作为参考,这是触发器:
-- =============================================
-- 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
时,它会给出与触发器开始时相同的结果。我看了几个例子,我正在努力弄清楚在这种特殊情况下究竟是什么让我的触发器有所不同。据我所知,根据编译器,第7行是ON [SalesForce].[dbo].[DistinctTest]
。
我也承认我对SQL编译器的工作方式知之甚少,所以我不知道“第7行”是否有可能实际上是用词不当而且错误是在身体中有一些逻辑我的代码但是,根据我的阅读,sp_helptext
生成了编译器实际读取的脚本的准确打印输出。我希望不必经历这个特定错误的整个触发器,因为它看起来很简单。
简单也是让我难过的原因 - 我在第7行附近没有看到额外的逗号,这个触发器的声明看起来与我在别处看到的大多数相同。我之前也做了一些测试触发器,但它们只针对一种DML操作而不是三种。
答案 0 :(得分:1)
引发错误是因为您的触发器具有动态sql,并且在包含在动态sql之前至少没有设置其中一个变量。这将导致无效的sql语句。如果要查看动态sql,可以在执行之前添加print或select语句来输出@SQL的内容。您必须使用SSMS来查看它,但它有助于调试。