用于插入新记录的sql server触发器

时间:2014-08-23 12:54:33

标签: sql-server-2008

我有一张名为' tblDive'列:

create table tblDive (
DiveNumber int
InstructorNumber int
ClubNumber int
InstructorSigniture date
)

和另一张表:

create table tblWorksAt (
InstructorNumber int
ClubNumber int
StartWorkingDate date
EndWorkingDate date
)

表' tblWorksAt'有这个记录:

InstructorNumber | ClubNumber | StartWorkingDate | EndWorkingDate
       1               2            1.1.2000          1.1.2005

我想创建一个触发器来检查插入新潜水的时间,如果教练在登录潜水的同时真的在这个俱乐部工作。 例如,如果我插入新的潜水:

insert into tblDive (DiveNumber InstructorNumber ClubNumber InstructorSigniture) 
values 111, 1, 2, 1.1.2009

我无法插入此记录,因为1号教练在2005年1月1日停止在2号俱乐部工作

2 个答案:

答案 0 :(得分:1)

使用触发器的替代方法是使用检查约束和用户定义的函数。

在正确的时间,在正确的俱乐部使用检查是指导员的功能:

CREATE FUNCTION CheckEmployment(@InstructorNumber int, @ClubNumber int, @checkdate date)
RETURNS int
AS 
BEGIN
   DECLARE @retval int
        SELECT @retval = COUNT(*) 
        FROM tblWorksAt 
        WHERE InstructorNumber = @InstructorNumber 
        AND ClubNumber = @ClubNumber
        AND (EndWorkingDate IS NULL OR EndWorkingDate > @checkdate)
   RETURN @retval
END;
GO

使用它的检查约束:

ALTER TABLE tblDive 
ADD CONSTRAINT chkEmployed 
CHECK (dbo.CheckEmployment(InstructorNumber, ClubNumber, InstructorSigniture) != 0);

这可能不是最有效的方法,但它应该完成工作。函数中的逻辑也可能需要改进,我可能错过了一些东西。

Sample SQL Fiddle显示它的实际效果。

答案 1 :(得分:0)

我要做的是给你一些提示和不太明显的关于可能帮助你编写触发器的触发器的信息,但需要写它。

inserted表格

在SQL Server触发器中,您可以引用2个伪表:inserteddeleted表。名字有点欺骗,特别是如果你正在做UPDATE。要记住的是,在引擎盖下,UPDATE是一个删除加插入。

基本上,inserted是新的(或更新的)行,deleted是在应用更改之前从UPDATE删除的行和/或前一行。

对于直接INSERT语句,deleted表应该为空。

因此,您希望在inserted中查找符合某组条件的行。有两种合理的方法可以解决这个问题:

  1. 检查所有行是否符合此条件
  2. 查找符合条件的行。
  3. <强>加入

    如果您加入insertedtblWorksAt,您现在拥有了所需的所有数据。这样的事情可以加入表并查找通过业务规则的行:

    select 1
    from inserted i
    inner join tblWorksAt wa on wa.InstructorNumber = i.InstructorNumber and i.ClubNumber = wa.ClubNumber
    where i.InstructorSignature between wa.StartWorkingDate and wa.EndWorkingDate
    

    如何处理查询

    就像我之前说过的那样:

    1. 检查所有行是否符合此条件
    2. 查找符合条件的行。
    3. 要检查所有行是否都符合该条件,您可以:

      1. 检查与该查询匹配的行数是否等于inserted中没有连接的总行数。
      2. inserted中的每一行循环,我现在会告诉你,在触发器中几乎不是一个好主意。
      3. 要检查至少有一行是否未能通过标准,您可以:

        1. between更改为not between,并围绕if (exists(...))包装此查询。
        2. inner join更改为left outer join,将where子句移动到连接,然后添加一个显示tblWorksAt.InstructorNumber is null的新WHERE子句,然后围绕if (exists(...))包装此查询
        3. 投掷错误

          现在您知道如何查找通过或失败的行。现在您只需要抛出一个错误来防止语句完成并阻止数据持久化。我将把它作为练习留给你。它应该很容易研究。