2

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

我有 1 个超类型表,其中包含在平台上注册的所有人员。我必须能够区分每个人的功能“候选人”和“考官”。所以我有 2 个子类型表,一个用于所有考生,一个用于所有考官。为此,我使用了插入触发器。

此外,一个人可以同时是候选人和考官,但不能同时是。因此,在更新超类型表之后,我还需要一个触发器,以便能够从两个子类型表中的一个中删除特定行,并在另一个上插入用户信息。

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

在此处输入图像描述

我的 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

我的更新触发器:

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 标识列时,必须为标识列指定显式值。

4

1 回答 1

0

一些简单的注释:

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

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] 添加约束 CK_alemp_persons_function_Verify CHECK (function 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)和之间的两个 FK [dbo].[alemp_persons](id_person, function)

这样,您可以确保该[dbo].[alemp_candidates]表只有候选人并且[dbo].[alemp_examiners]只有考官,并且每个人一次只能是候选人或考官。

6) 您应该禁止和表 ( )中的列的IDENTITY属性。id_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
于 2013-04-07T16:52:14.763 回答