更新触发器:超类型/子类型表

时间:2013-03-16 01:42:41

标签: sql-server-2008 triggers insert-update subtype supertype

我需要一些关于触发器的帮助。我目前正在开发一个平台和一个数据库,以便管理我大学的考试。这是我的问题:

我有1个超类型表,其中包含平台上注册的所有人员。我必须能够在“候选人”和“审查员”这两个职能之间区分每个人。所以我有2个子类型表,一个用于所有候选人,一个用于所有审查员。为此,我正在使用插入触发器。

此外,一个人既可以是候选人也可以是考官,但不能同时进行。所以在更新超类型表之后,我还需要一个触发器来从一个双子类型表中删除一个特定的行,并将用户信息插入到另一个子类中。

以下是这3个表的简化设计:

enter image description here

我的INSERT触发器:

ALTER TRIGGER [dbo].[role_insert]   
ON [dbo].[alemp_persons]  
FOR INSERT  
AS
  DECLARE @random_number int
  SELECT @random_number = CAST(CAST(rand() as binary(2)) as int)
BEGIN
  INSERT INTO dbo.alemp_candidates 
  ( 
  id_person, random_number
  )  
  SELECT id_person, @ random_number
  FROM INSERTED  
  WHERE function='Candidate'

  INSERT INTO dbo.alemp_examiners
  (  
  id_person
  )  
  SELECT id_person
  FROM INSERTED  
  Where function='Examiner'
END
GO

我的UPDATE触发器:

ALTER TRIGGER [dbo].[role_update] ON [dbo].[alemp_persons]
AFTER UPDATE
AS
  DECLARE @id_person int 
  DECLARE @newFunction int SELECT @newFunction=function FROM inserted
  DECLARE @random_number int SELECT @ random_number = CAST(CAST(rand() as binary(2)) as int)

IF @newFunction = 'Candidate'
BEGIN
  DELETE
  FROM dbo.alemp_examiners
  WHERE id_person=@id_person
END

BEGIN
  SET IDENTITY_INSERT dbo.alemp_candidates ON;
  INSERT INTO dbo.alemp_candidates  
  (  
  id_person, random_number
  )  
  SELECT  @id_person, random_number
  SET IDENTITY_INSERT dbo.alemp_candidates OFF;
END

IF @newFunction = 'Examiner'
BEGIN
  DELETE 
  FROM dbo.alemp_candidates
  WHERE id_person=@id_person
END

BEGIN
  SET IDENTITY_INSERT dbo.alemp_examiners ON;
  INSERT INTO dbo.alemp_examiners
  (  
  id_person
  ) 
  SELECT  @id_person
  SET IDENTITY_INSERT dbo.alemp_examiners Off;
END
GO

正如我上面所说,我的INSERT触发器可以正常工作。但是,当我想更新一个人的功能时,我收到了一个错误:

  

设置IDENTITY_INSERT时,必须为标识列指定显式值   到ON或复制用户插入NOT FOR REPLICATION标识列时。

1 个答案:

答案 0 :(得分:0)

一些简单的说明:

1)您应该遵循Mitch Wheat的建议并重写这些触发器,因为inserteddeleted表可能有多行。例如,如果第一个人的函数是“Examiner”且第二个人的函数是“Candidate”,那么当执行下一个语句UPDATE [dbo].[alemp_persons] SET function = CASE WHEN id_person = 1 THEN 'Candidate' ELSE 'Examiner' END WHERE id_person IN (1,2)时,你的触发器会有不良行为。

2)[dbo].[alemp_persons].function的数据类型应为[tiny]intchar(1)而不是varchar(something greater than 1)Where function='Examiner')。

3)[dbo].[alemp_persons].function列应该禁止Null。

4)[dbo].[alemp_persons].function列应具有CHECK约束:

ALTER TABLE [dbo]。[alemp_persons] ADD CONSTRAINT CK_alemp_persons_function_Verify CHECK(函数IN('Candidate','Examiner'));

5)添加

会很不错
  • function列到[dbo].[alemp_candidates][dbo].[alemp_examiners]表,

  • [dbo].[alemp_candidates]function = 'Candidate')和[dbo].[alemp_examiners]function = 'Examiner'),

  • 的两项检查限制
  • [dbo].[alemp_persons](id_person, function)上的唯一索引,

  • [dbo].[alemp_candidates/examiners](id_person, function)[dbo].[alemp_persons](id_person, function)之间的两个FK。

这样,您可以确保[dbo].[alemp_candidates]表只有候选人,[dbo].[alemp_examiners]只有审查员,而且每个人一次只能成为候选人或审查员。

6)您应该禁止IDENTITYid_person表([dbo].[alemp_candidates])中[dbo].[alemp_examiners]列的SET IDENTITY_INSERT dbo.alemp_candidates ...属性。

8)此语句IF @newFunction = 'Candidate'应该引发错误,因为@newFunction数据类型为'INT'。

9)AFTER UPDATE表上的[dbo].[alemp_persons]触发器将在候选人和审查员表之间移动数据(未经测试):

ALTER TRIGGER [dbo].[role_update]   
ON [dbo].[alemp_persons]  
FOR UPDATE
AS
BEGIN

DECLARE @selected_rows TABLE (
id_person INT PRIMARY KEY, -- or BIGINT, look at alemp_person.id_person data type 
new_function VARCHAR(50) NOT NULL -- look at alemp_person.function column data type 
);

INSERT @selected_rows (id_person, new_function)
SELECT new.id_person, new.function
FROM inserted as new INNER JOIN deleted as old ON new.id_person = old.id_person
WHERE new.function <> old.function;

MERGER dbo.alemp_candidates AS dest
USING @selected_rows AS src ON dest.id_person = src.id_person
WHEN MATCHED THEN 
    DELETE
WHEN NOT MATCHED BY TARGET AND src.new_function = 'Candidate' THEN
    INSERT (id_person, random_number)
    VALUES (src.id_person, CONVERT(BINARY(2), CHECKSUM(NEWID()));

MERGER dbo.alemp_examiners AS dest
USING @selected_rows AS src ON dest.id_person = src.id_person
WHEN MATCHED THEN 
    DELETE
WHEN NOT MATCHED BY TARGET AND src.new_function = 'Examiner' THEN
    INSERT (id_person)
    VALUES (src.id_person);
END