引发重复预防的触发器
Raise trigger for duplicate prevention
如果将重复项插入 table movie_cast$
,我将尝试引发触发器。但是即使插入重复项也不会引发错误。这是存储过程和触发器。请帮忙
create or alter procedure up_cast_actor
@actor_id integer,
@mov_id integer,
@role_Name varchar(122)
as
begin
set nocount on
insert into movie_cast$
values (@actor_id, @mov_id, @role_name);
end;
go
create or alter trigger prevent_recast
on movie_cast$
after update
as
begin
set nocount on
if exists (
select *
from movie_cast$ as t
inner join inserted i on
i.mov_id = t.mov_id
and i.act_id = t.act_id
and i.role = t.role
)
begin
--rollback
raiserror( -20001, -1,-1, 'This actor is already cast for this movie.'); --to restrict the insetion`.
RAISERROR ('Duplicate Data', 16, 1);
end;
end;
go
EXECUTE up_cast_actor 124, 921, 'raj';
EXECUTE up_cast_actor 124, 928, 'rob';
EXECUTE up_cast_actor 124, 921, 'raj';
就像我在评论中提到的那样,当有一个特定的对象类型时,使用 TRIGGER
是没有意义的:UNIQUE CONSTRAINT
.
--Sample Table
CREATE TABLE dbo.MovieCast (CastID int IDENTITY(1,1),
ActorID int NOT NULL,
MovieID int NOT NULL,
RoleName nvarchar(50));
GO
--Add Constraint
ALTER TABLE dbo.MovieCast ADD CONSTRAINT UQ_MovieActor_MovieCast UNIQUE (ActorID,MovieID);
GO
--Sample Attempts
INSERT INTO dbo.MovieCast (ActorID,
MovieID,
RoleName)
VALUES(124, 921, 'raj'); --Success
GO
INSERT INTO dbo.MovieCast (ActorID,
MovieID,
RoleName)
VALUES(124, 928, 'rob'); --Success
GO
INSERT INTO dbo.MovieCast (ActorID,
MovieID,
RoleName)
VALUES(124, 921, 'Jon'); --Fails
GO
--Clean up
DROP TABLE dbo.MovieCast;
第一:你忘记了一个ROLLBACK语句来取消事务
其次:你忘了数(HAVING)
第三:您没有正确的 RAISERROR 语法
代码必须是:
CREATE OR ALTER TRIGGER prevent_recast
ON movie_cast$
AFTER INSERT, UPDATE
AS
SET NOCOUNT ON
IF NOT EXISTS (SELECT *
FROM movie_cast$ as t
JOIN inserted i
ON i.mov_id = t.mov_id
AND i.act_id = t.act_id
AND i.role = t.role
HAVING COUNT(*) = 1)
RETURN;
ROLLBACK;
RAISERROR('Duplicate Data : this actor is already cast for this movie.', 16, 1);
GO
当然正如@Larnu 所说,取消由解释代码 (Transact SQL) 组成并在 INSERT 之后运行的事务而不是使用 UNIQUE 约束是愚蠢的事情在 C 语言中运行并在插入之前执行 !
约束将很简单:
ALTER TABLE movie_cast$
ADD UNIQUE (actor_id, mov_id, role_name);
请不要修改我的代码...只是建议一些修正
回应OP的:
the reason for using a trigger and stored procedure was because this was specifically asked to be done.
A UNIQUE CONSTRAINT
/UNIQUE INDEX
是这里的正确解决方案,而且它很可能会快得多。也就是说,您可以使用 TRIGGER
和 THROW
调用 SQL.
的错误来执行此操作
--Sample Table
CREATE TABLE dbo.MovieCast (CastID int IDENTITY(1,1),
ActorID int NOT NULL,
MovieID int NOT NULL,
RoleName nvarchar(50));
GO
CREATE TRIGGER dbo.trg_UQ_MovieActor_MovieCast ON dbo.MovieCast
AFTER INSERT, UPDATE AS
BEGIN
SET NOCOUNT ON;
IF EXISTS (SELECT 1
FROM dbo.MovieCast MC
GROUP BY MC.ActorID, MC.MovieID
HAVING COUNT(*) > 1)
THROW 55555, --Use a bespoke error number for your environment
N'A duplicate row has been detected in the trigger ''trg_UQ_MovieActor_MovieCast''. Cannot insert/update duplicate row in object ''dbo.MovieCast''.',
16;
END;
GO
--Sample Attempts
INSERT INTO dbo.MovieCast (ActorID,
MovieID,
RoleName)
VALUES(124, 921, 'raj'); --Success
GO
INSERT INTO dbo.MovieCast (ActorID,
MovieID,
RoleName)
VALUES(124, 928, 'rob'); --Success
GO
INSERT INTO dbo.MovieCast (ActorID,
MovieID,
RoleName)
VALUES(124, 921, 'Jon'); --Fails
GO
SELECT *
FROM dbo.MovieCast;
GO
--Clean up
DROP TABLE dbo.MovieCast;
请注意,与 UNIQUE CONSTRAINT
不同,您不会被告知导致错误的行,这意味着对于影响多行的语句,这会使调试变得更加困难。
单独回答,因为问题中从未提出需要 TRIGGER
的要求,我的原始答案回答了最初提出的问题。
此外,虽然与 相似,但我不同意他们使用 RAISERROR
和 ROLLBACK
,所以我展示了 THROW
应该使用。
如果将重复项插入 table movie_cast$
,我将尝试引发触发器。但是即使插入重复项也不会引发错误。这是存储过程和触发器。请帮忙
create or alter procedure up_cast_actor
@actor_id integer,
@mov_id integer,
@role_Name varchar(122)
as
begin
set nocount on
insert into movie_cast$
values (@actor_id, @mov_id, @role_name);
end;
go
create or alter trigger prevent_recast
on movie_cast$
after update
as
begin
set nocount on
if exists (
select *
from movie_cast$ as t
inner join inserted i on
i.mov_id = t.mov_id
and i.act_id = t.act_id
and i.role = t.role
)
begin
--rollback
raiserror( -20001, -1,-1, 'This actor is already cast for this movie.'); --to restrict the insetion`.
RAISERROR ('Duplicate Data', 16, 1);
end;
end;
go
EXECUTE up_cast_actor 124, 921, 'raj';
EXECUTE up_cast_actor 124, 928, 'rob';
EXECUTE up_cast_actor 124, 921, 'raj';
就像我在评论中提到的那样,当有一个特定的对象类型时,使用 TRIGGER
是没有意义的:UNIQUE CONSTRAINT
.
--Sample Table
CREATE TABLE dbo.MovieCast (CastID int IDENTITY(1,1),
ActorID int NOT NULL,
MovieID int NOT NULL,
RoleName nvarchar(50));
GO
--Add Constraint
ALTER TABLE dbo.MovieCast ADD CONSTRAINT UQ_MovieActor_MovieCast UNIQUE (ActorID,MovieID);
GO
--Sample Attempts
INSERT INTO dbo.MovieCast (ActorID,
MovieID,
RoleName)
VALUES(124, 921, 'raj'); --Success
GO
INSERT INTO dbo.MovieCast (ActorID,
MovieID,
RoleName)
VALUES(124, 928, 'rob'); --Success
GO
INSERT INTO dbo.MovieCast (ActorID,
MovieID,
RoleName)
VALUES(124, 921, 'Jon'); --Fails
GO
--Clean up
DROP TABLE dbo.MovieCast;
第一:你忘记了一个ROLLBACK语句来取消事务
其次:你忘了数(HAVING)
第三:您没有正确的 RAISERROR 语法
代码必须是:
CREATE OR ALTER TRIGGER prevent_recast
ON movie_cast$
AFTER INSERT, UPDATE
AS
SET NOCOUNT ON
IF NOT EXISTS (SELECT *
FROM movie_cast$ as t
JOIN inserted i
ON i.mov_id = t.mov_id
AND i.act_id = t.act_id
AND i.role = t.role
HAVING COUNT(*) = 1)
RETURN;
ROLLBACK;
RAISERROR('Duplicate Data : this actor is already cast for this movie.', 16, 1);
GO
当然正如@Larnu 所说,取消由解释代码 (Transact SQL) 组成并在 INSERT 之后运行的事务而不是使用 UNIQUE 约束是愚蠢的事情在 C 语言中运行并在插入之前执行 !
约束将很简单:
ALTER TABLE movie_cast$
ADD UNIQUE (actor_id, mov_id, role_name);
请不要修改我的代码...只是建议一些修正
回应OP的
the reason for using a trigger and stored procedure was because this was specifically asked to be done.
A UNIQUE CONSTRAINT
/UNIQUE INDEX
是这里的正确解决方案,而且它很可能会快得多。也就是说,您可以使用 TRIGGER
和 THROW
调用 SQL.
--Sample Table
CREATE TABLE dbo.MovieCast (CastID int IDENTITY(1,1),
ActorID int NOT NULL,
MovieID int NOT NULL,
RoleName nvarchar(50));
GO
CREATE TRIGGER dbo.trg_UQ_MovieActor_MovieCast ON dbo.MovieCast
AFTER INSERT, UPDATE AS
BEGIN
SET NOCOUNT ON;
IF EXISTS (SELECT 1
FROM dbo.MovieCast MC
GROUP BY MC.ActorID, MC.MovieID
HAVING COUNT(*) > 1)
THROW 55555, --Use a bespoke error number for your environment
N'A duplicate row has been detected in the trigger ''trg_UQ_MovieActor_MovieCast''. Cannot insert/update duplicate row in object ''dbo.MovieCast''.',
16;
END;
GO
--Sample Attempts
INSERT INTO dbo.MovieCast (ActorID,
MovieID,
RoleName)
VALUES(124, 921, 'raj'); --Success
GO
INSERT INTO dbo.MovieCast (ActorID,
MovieID,
RoleName)
VALUES(124, 928, 'rob'); --Success
GO
INSERT INTO dbo.MovieCast (ActorID,
MovieID,
RoleName)
VALUES(124, 921, 'Jon'); --Fails
GO
SELECT *
FROM dbo.MovieCast;
GO
--Clean up
DROP TABLE dbo.MovieCast;
请注意,与 UNIQUE CONSTRAINT
不同,您不会被告知导致错误的行,这意味着对于影响多行的语句,这会使调试变得更加困难。
单独回答,因为问题中从未提出需要 TRIGGER
的要求,我的原始答案回答了最初提出的问题。
此外,虽然与 RAISERROR
和 ROLLBACK
,所以我展示了 THROW
应该使用。