我需要一些关于触发器的帮助。我目前正在开发一个平台和一个数据库,以便管理我大学的考试。这是我的问题:
我有1个超类型表,其中包含平台上注册的所有人员。我必须能够在“候选人”和“审查员”这两个职能之间区分每个人。所以我有2个子类型表,一个用于所有候选人,一个用于所有审查员。为此,我正在使用插入触发器。
此外,一个人既可以是候选人也可以是考官,但不能同时进行。所以在更新超类型表之后,我还需要一个触发器来从一个双子类型表中删除一个特定的行,并将用户信息插入到另一个子类中。
以下是这3个表的简化设计:
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标识列时。
答案 0 :(得分:0)
一些简单的说明:
1)您应该遵循Mitch Wheat的建议并重写这些触发器,因为inserted
和deleted
表可能有多行。例如,如果第一个人的函数是“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]int
或char(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)您应该禁止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