почему триггер не работает?

у меня есть таблица в которой два столба id предметов и названия предметов, мне надо создать триггер, который если такого предмета нету в таблице добавлял его, а если есть, то выводил текст, что такой предмет уже есть и не добавлял его вот мой код

GO
CREATE TRIGGER AddingDiscipline
ON Disciplines
FOR INSERT
AS
DECLARE @Subjects VARCHAR(150)
SELECT @Subjects=Subjects
FROM inserted
IF EXISTS (SELECT Subjects FROM Disciplines where @Subjects=Disciplines.Subjects)
BEGIN 
PRINT 'Предмет уже есть'
ROLLBACK TRANSACTION
END

Ответы (1 шт):

Автор решения: teran

вы пишите триггер after insert, который на саму вставку никак не влияет, а требуется вам триггер instead of insert.

Далее, следует учесть, что в случае множественной вставки INSERT ... VALUES ('qwe'), ('asd'); в таблицу inserted попадает не одна строка, а все. Поэтому ваша переменная @subjects примет последнее значение из вставляемых строк. Следовательно при множественной вставке результат будет некорректен.

Поэтому, если хотите забраковать всю вставку при наличии совпадающих, то надо джойнить inserted на исходную по полю и проводить вставку только в случае, когда выборка не пуста.

ALTER TRIGGER trg_DisciplinesInsert ON disciplines INSTEAD OF INSERT AS 


    IF NOT EXISTS(
        SELECT 1
        FROM inserted AS i
        INNER JOIN disciplines AS d ON (d.title = ltrim(rtrim(i.title)))
    ) BEGIN
        INSERT INTO disciplines (title) 
        SELECT DISTINCT ltrim(rtrim(title)) FROM inserted;      
    END
    ELSE PRINT 'Есть дубликаты';        

откат тут в целом не нужен, ибо в случае дубля фактическая вставка не производится.

как вариант, вы можете вставить только новые строки

ALTER TRIGGER trg_DisciplinesInsert ON disciplines INSTEAD OF INSERT AS 

    INSERT INTO disciplines (title) OUTPUT inserted.*
    SELECT ltrim(rtrim(i.title))
    FROM inserted AS i
    LEFT JOIN disciplines AS d ON d.title = ltrim(rtrim(i.title))
    WHERE d.id IS NULL

В итоге, если вам таки надо вывести сами дубли текстом, то можно сначала зайджойнить новые строки с имеющимися и результат вставить во временную. Потом глянуть, если есть старые, то вывести их (в новых версиях использовать string_agg). Новые строки вставить, можно также вывести вставку через OUTPUT.

ALTER TRIGGER trg_DisciplinesInsert ON disciplines INSTEAD OF INSERT AS 

    DECLARE @dups TABLE (old_id int null, title varchar(255) );
    set nocount ON;

    INSERT INTO @dups (old_id, title) 
    SELECT d.id, ltrim(rtrim(i.title))
    FROM inserted AS i
    LEFT JOIN disciplines AS d ON d.title = ltrim(rtrim(i.title));      
        
    IF EXISTS(SELECT 1 FROM @dups WHERE old_id > 0) BEGIN
        DECLARE @x VARCHAR(MAX) = ( STUFF((SELECT ', ' + title FROM @dups WHERE old_id > 0 FOR XML PATH('')), 1, 2, ''));
        PRINT 'dups: ' + @x;;
    END;
    
    
    INSERT INTO disciplines (title) OUTPUT inserted.*
    SELECT title FROM @dups WHERE old_id IS NULL;   
→ Ссылка