【发布时间】:2012-12-22 15:52:34
【问题描述】:
我被告知要在我们的 SQL Server 2000 上为 插入 创建一个触发器。
我以前从未编写过触发器,而且我们的旧服务器上似乎没有定义任何触发器。
按照Triggers in SQL Server 教程,我创建了这个尚未执行的触发器:
create trigger trgAfterMachine1Insert on Test_Results
after insert
as
declare @sn varchar(20), @sysID varchar(50),
@opID varchar(50), @testResult varchar(255)
select @sn=Serial_Number from inserted
select @sysID=System_ID from inserted
select @opID=Op_ID from inserted
select @testResult=Test_Result from inserted
exec sp1_AddSnRecord(@sn, @sysID, @opID, @testResult)
print 'Machine1 After Insert Trigger called AddSnRecord'
go
首先,请注意我已经编写了一个名为sp1_AddSnRecord 的存储过程来将此数据插入到一个新表中(所以我不会弄乱现有表)。我当然希望可以在触发器上调用存储过程,因为它会在将任何内容插入其他表之前对数据执行数据验证和枚举。
我真的看不到在 SQL Server 2000 中测试这是否可行的方法,而且我对在 Management Studio 中点击 执行 按钮有点紧张。
所以,我已经研究了一段时间,并尝试了解其他一些 SO 技术。
从Aaron Bertrand 的示例HERE 看来,我可以将所有选择调用合并到一行中:
create trigger trgAfterMachine1Insert on Test_Results
after insert
as
declare @sn varchar(20), @sysID varchar(50),
@opID varchar(50), @testResult varchar(255)
select @sn=Serial_Number, @sysID=System_ID,
@opID=Op_ID, @testResult=Test_Result
from inserted
exec sp1_AddSnRecord(@sn, @sysID, @opID, @testResult)
print 'Machine1 After Insert Trigger called AddSnRecord'
go
否则,我在任何地方都看不到任何更有启发性的东西,或者看到有人询问在创建触发器之前测试触发器的技术。
我在这里工作的一所大学做的 SQL 工作比我多,但他承认他从未编写过触发器。他只能告诉我,“伙计,如果你搞砸了,你可能会在服务器上造成很多问题!” 所做的只是让我紧张,这就是我为什么这里。 (我所做的 98% 是为 Windows 窗体和旧的 Windows Mobile 设备编写 C# 代码)。
那么,我将如何验证此触发器是否有效并且在创建之前不会在服务器上造成任何问题?我的机器上有一个本地 SQL Server Express,但它比 SQL 2000 更新得多,并且没有从我们的生产车间运行的实时数据。
如果事后证明触发器有故障,我可以使用简单的delete trigger trgAfterMachine1Insert 将其删除吗?我对“删除触发器”的搜索似乎主要返回了 AFTER DELETE 的触发器。
提前致谢。
更新:应马丁的要求包括存储过程:
ALTER PROCEDURE [dbo].[sp1_AddSnRecord](
@serial_Number varchar(20),
@system_ID varchar(50),
@op_ID varchar(50),
@test_Result varchar(255)) as begin
set NOCOUNT ON;
declare @sn as VarChar(20);
set @sn=dbo.fn_ValidSN(@serial_Number);
if (7<Len(@sn)) begin
declare @badge varchar(50), @result varchar(50), @sysID varchar(50);
set @badge=dbo.fn_GetBadge(@op_ID);
set @result=dbo.fn_GetTestResult(@test_Result);
set @sysID=dbo.fn_GetSysType(@system_ID);
if ((0<Len(@badge)) and (0<Len(@result)) and (0<Len(@sysID))) begin
declare @id int;
select @id=ID from Serial_Numbers where Serial_Number=@sn;
if (@id<1) begin -- this serial number has not been entered
insert into Serial_Numbers (Serial_Number) values (@sn);
select @id=@@IDENTITY from Serial_Numbers;
end
if (0<@id) begin -- now insert into SN_Records
insert into SN_Records (SN_ID, SYS_ID, OP_ID, Date_Time, Test_Result)
values (@id, @sysID, @badge, GetDate(), @result);
end
end
end
end
【问题讨论】:
-
如果在一条语句中插入多行,您的触发器将失败。比那个教程更好地看在线书籍。要调用存储过程,您需要使用游标遍历插入的所有行。
-
听起来您最大的问题是您没有一个准确(或足够好)生产副本的测试数据库。你为什么不先解决这个问题,然后你可以随心所欲地进行实验。
-
需要考虑的内容很多。最后,您可以使用
DROP TRIGGER删除触发器。也就是说,您的触发器有一个潜在的主要问题:您通过从inserted表中选择来分配变量,但是如果您一次插入多个记录,您的inserted表中将有多个记录,并且选择变量将不起作用。 -
刚刚注意到存储过程是您刚刚编写的。在这种情况下,最好摆脱它并在触发器中设置逻辑。你能发布代码吗?
-
而不是使用
@@IDENTITY并逐行执行(代码无论如何看起来都是错误的)最好在一个语句中插入Serial_Numbers中不存在的所有行INSERTED然后您的第二个insert into SN_Records可以加入Serial_Numbers以获取所有行的ID并同时插入所有行。不过真的不想在我的 ipad 上构建一个完整的示例。
标签: sql tsql triggers sql-server-2000