【问题标题】:Validate new Create Trigger for SQL Server 2000验证 SQL Server 2000 的新创建触发器
【发布时间】: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


【解决方案1】:

所以,让我重新表述一下你的意思:

  • 您没有编写触发器的经验
  • 公司中没有其他人有编写触发器的经验
  • 您只有生产环境,没有其他地方可以测试您的代码
  • 管理层告诉你今晚之前完成这项工作

这肯定是灾难的根源。

首先,您需要反对您唯一选择失败的请求。告诉管理层他们的数据太重要了,如果没有适当的测试,就不能做这样的事情。

然后得到一个合适的测试环境。如果您的公司是 MSDN 订阅者,您将可以访问 SQL Server 2000 Developer Edition 的副本,您可以将其安装在您的笔记本电脑上,或者更好地安装在某些虚拟机中。

在等待安装时,请阅读有关软件开发专业行为的信息。从http://en.wikipedia.org/wiki/Robert_Cecil_Martin开始,再到软件工艺。


但是,我知道今晚不会发生这种情况,您可以在此期间执行此操作:

1) 在生产服务器上新建数据库

2) 复制有问题的表:SELECT TOP(10) * INTO NewDb.dbo.Table FROM OldDb.dbo.Table; 您不需要更多数据,因为这是一个插入触发器

3) 用同样的方法复制你需要的其他表

4) 将触发器应用到 NewDb 中的表

5) 测试

6) 修复并返回 5

7) 如果满意,将触发器复制到 OldDb

需要考虑的一些事项:

  • 确保您测试多于一行的插入
  • 不要在触发器中调用过程。并不是说这本身就是错误的,但是您将无法使用它进行多行插入
  • 永远不要使用@@IDENTITY。那是命令。 (原因和解决方法在这里:http://sqlity.net/en/351/identity-crisis/

在此处开始查看数据库中的 TDD:tSQLt.org (大多数想法都适用于 SQL 2000,但框架却不行。)

希望对您有所帮助。

【讨论】:

  • 如果可以的话,我会投票一百万次。这绝对是灾难的秘诀。我唯一要补充的是,这家公司需要为他们的员工增加一名数据库专家(当然他们也应该有一个开发环境;允许开发人员直接对产品进行更改肯定是管理层无能的标志!) .触发器不应由 SQL 专家以外的任何人编写,因为如果编写不正确,它们可能会导致可怕的问题。这不适用于应用程序开发人员。
  • 感谢塞巴斯蒂安!你昨天也帮了我。在我的触发器中,如果inserted 参数返回多行,我该如何处理?如果我需要编辑此触发器,是否要先删除触发器并重新创建它?我不知道如何找到活动触发器。
  • INSERTED 虚拟表可以像使用任何其他表一样使用。所以你可以在触发器中做一个INSERT INTO dbo.MyTable(&lt;columnlist&gt;) SELECT &lt;columnlist&gt; FROM INSERTED。首先创建缺少的序列号,然后通过将INSERTED 加入序列号来创建 SN_Records。所有的 IF 逻辑都可以放入 CASE 语句中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-04
  • 2011-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-07
  • 1970-01-01
相关资源
最近更新 更多