引发重复预防的触发器

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 是这里的正确解决方案,而且它很可能会快得多。也就是说,您可以使用 TRIGGERTHROW 调用 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 的要求,我的原始答案回答了最初提出的问题。

此外,虽然与 相似,但我不同意他们使用 RAISERRORROLLBACK,所以我展示了 THROW应该使用。