Вставте тригер оновлення, як визначити, вставити чи оновити


162

Мені потрібно написати вставку, оновити тригер в таблицю A, яка видалить усі рядки з таблиці B, в одному стовпчику (скажімо, Desc) є такі значення, як значення, вставлене / оновлене у стовпці таблиці A (скажімо, Col1). Як би я не пішов писати це, щоб я міг обробляти і оновлення, і вставки. Як я можу визначити, чи виконується тригер для оновлення чи вставки.

Відповіді:


167

Тригери мають спеціальні INSERTEDта DELETEDтаблиці для відстеження даних "до" та "після". Таким чином, ви можете використовувати щось на кшталт IF EXISTS (SELECT * FROM DELETED)виявлення оновлення. Ви DELETEDоновлюєте лише рядки , але в них завжди є рядкиINSERTED .

Шукайте "вставлений" у CREATE TRIGGER .

Редагувати, 23 листопада 2011 року

Після коментаря ця відповідь лише для INSERTEDі UPDATEDвикликає.
Очевидно, що тригери DELETE не можуть мати "завжди рядки INSERTED", як я вже говорив вище


Подивіться нижче на відповідь @ MikeTeeVee, щоб отримати повну відповідь. Цей є неповним.
Лоренц Мейєр

1
Оригінальне запитання @LorenzMeyer цього не потребує. У мене також є ЕКСИСТИ (ВИБРАТИ * З ВІДКРИТТЯ). Не впевнений, чому ви вважаєте, що це не повно…
gbn

Те, на що @LorenzMeyer також може посилатися, - це твердження "У вас є лише рядки У ВІДКЛЮЧЕНОМ при оновленні, але завжди є рядки ВСТАНОВЛЕНО ". Це не завжди відповідає дійсності, тому що бувають випадки, коли тригер оновлення / вставлення викликається і ВКАЗАНО порожній. У своїй відповіді я пояснюю, як це може бути спричинене тим, що предикат виключає будь-які дані від зміни. У цьому випадку тригер все ще викликається спробою DML, але таблиці ВИДАЛЕНІ та ВСТАНОВІ порожні. Це пояснюється тим, що SQL все ще припадає на часи, коли ви бажаєте реєструвати кожну спробу DML (навіть коли вони не змінюють жодних даних).
MikeTeeVee

127
CREATE TRIGGER dbo.TableName_IUD
ON dbo.TableName
AFTER INSERT, UPDATE, DELETE
AS 
BEGIN
    SET NOCOUNT ON;

    --
    -- Check if this is an INSERT, UPDATE or DELETE Action.
    -- 
    DECLARE @action as char(1);

    SET @action = 'I'; -- Set Action to Insert by default.
    IF EXISTS(SELECT * FROM DELETED)
    BEGIN
        SET @action = 
            CASE
                WHEN EXISTS(SELECT * FROM INSERTED) THEN 'U' -- Set Action to Updated.
                ELSE 'D' -- Set Action to Deleted.       
            END
    END
    ELSE 
        IF NOT EXISTS(SELECT * FROM INSERTED) RETURN; -- Nothing updated or inserted.

    ...

    END

1
Мені також подобається писати SELECT 1 З ВСТАНОВЛЕНОГО, тому що я думаю, що це сигналізує про наміри більш чітко, але я би був знешкоджений програмістами MSSQL, якщо це має значення в цьому контексті ...
Lukáš Lánský

26
ЯКЩО існують (SELECT * ...) та IF EXISTS (SELECT 1) ... мають однакову продуктивність. Рядок взагалі не читається і не вибирається. Насправді ви також можете використовувати IF EXISTS (SELECT 1/0 ...), і він все одно буде працювати і не спричинить поділ на нульову помилку.
Endrju

1
Я створював окремі тригери для вставки, оновлення та видалення. Тепер чудово знати, що їх можна комбінувати!
UJS

2
Якщо хтось пише запит на ВСТАВЛЕННЯ та ВИДАЛЕННЯ двох різних рядків (вставити нову рядок та видалити інший рядок у тому самому сценарії), чи можливо, тригер, встановлений способом вище, насправді ідентифікує це як ОНОВЛЕННЯ (навіть якщо наміри насправді не є оновленням) через те, що в таблиці ВСТАНОВЛЕНІ / ВИДАЛЕНІ sql-таблиці є дані?
мче

87

Багато цих пропозицій не враховуються, якщо ви запустите операцію видалення, яка нічого не видаляє.
Скажімо, ви намагаєтесь видалити, де ідентифікатор дорівнює деякому значенню, яке не існує в таблиці.
Ваш тригер все ще викликається, але в таблицях Видалених або Вставлених нічого немає.

Використовуйте це для безпечності:

--Determine if this is an INSERT,UPDATE, or DELETE Action or a "failed delete".
DECLARE @Action as char(1);
    SET @Action = (CASE WHEN EXISTS(SELECT * FROM INSERTED)
                         AND EXISTS(SELECT * FROM DELETED)
                        THEN 'U'  -- Set Action to Updated.
                        WHEN EXISTS(SELECT * FROM INSERTED)
                        THEN 'I'  -- Set Action to Insert.
                        WHEN EXISTS(SELECT * FROM DELETED)
                        THEN 'D'  -- Set Action to Deleted.
                        ELSE NULL -- Skip. It may have been a "failed delete".   
                    END)

Особлива подяка @KenDog та @Net_Prog за їх відповіді.
Я будував це зі своїх сценаріїв.


3
Цей приз - це обробка неіснуючих видалених. Гарна робота!
Ендрю Вулф

6
Ми також можемо мати ОНОВЛЕННЯ, яке не вплинуло на рядки (або навіть ВСТАВКА).
Разван Сокол

@AndrewWolfe? Що ти кажеш? У запитанні конкретно зазначено, що "мені потрібно написати вставку, оновити тригер в таблицю A" . Нічого про тригери DELETE.
ypercubeᵀᴹ

@ ypercubeᵀᴹ Вибачте, приблизно 80% моїх тригерів охоплюють усі три таймінги.
Ендрю Вулф

18

Я використовую наступне, він також правильно виявляє заяви видалення, які нічого не видаляють:

CREATE TRIGGER dbo.TR_TableName_TriggerName
    ON dbo.TableName
    AFTER INSERT, UPDATE, DELETE
AS
BEGIN
    SET NOCOUNT ON;

    IF NOT EXISTS(SELECT * FROM INSERTED)
        -- DELETE
        PRINT 'DELETE';
    ELSE
    BEGIN
        IF NOT EXISTS(SELECT * FROM DELETED)
            -- INSERT
            PRINT 'INSERT';
        ELSE
            -- UPDATE
            PRINT 'UPDATE';
    END
END;

4
цей неправильно виявляє заяви, які нічого не вставляють або нічого не оновлюють.
Роман Пекар

11

Після багатьох пошуків я не зміг знайти точного прикладу одного тригера SQL Server, який обробляє всі (3) три умови дії тригера INSERT, UPDATE та DELETE. Нарешті я знайшов рядок тексту, який розповідав про те, що коли відбувається ВИДАЛЕННЯ або ОНОВЛЕННЯ, загальна таблиця ВИДАЛЕНО буде містити запис для цих двох дій. На основі цієї інформації я тоді створив невелику процедуру дії, яка визначає, чому тригер був активований. Цей тип інтерфейсу іноді необхідний, коли на тригері INSERT проти UPDATE відбувається як загальна конфігурація, так і конкретна дія. У цих випадках створення окремого тригера для UPDATE та INSERT стане проблемою з технічним обслуговуванням. .

З цією метою я хотів би дати наступний фрагмент коду подій для декількох тригерів для обробки INSERT, UPDATE, DELETE в одному тригері для Microsoft SQL Server.

CREATE TRIGGER [dbo].[INSUPDDEL_MyDataTable]
ON [dbo].[MyDataTable] FOR INSERT, UPDATE, DELETE
AS 

-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with caller queries SELECT statements.
-- If an update/insert/delete occurs on the main table, the number of records affected
-- should only be based on that table and not what records the triggers may/may not
-- select.
SET NOCOUNT ON;

--
-- Variables Needed for this Trigger
-- 
DECLARE @PACKLIST_ID varchar(15)
DECLARE @LINE_NO smallint
DECLARE @SHIPPED_QTY decimal(14,4)
DECLARE @CUST_ORDER_ID varchar(15)
--
-- Determine if this is an INSERT,UPDATE, or DELETE Action
-- 
DECLARE @Action as char(1)
DECLARE @Count as int
SET @Action = 'I' -- Set Action to 'I'nsert by default.
SELECT @Count = COUNT(*) FROM DELETED
if @Count > 0
    BEGIN
        SET @Action = 'D' -- Set Action to 'D'eleted.
        SELECT @Count = COUNT(*) FROM INSERTED
        IF @Count > 0
            SET @Action = 'U' -- Set Action to 'U'pdated.
    END

if @Action = 'D'
    -- This is a DELETE Record Action
    --
    BEGIN
        SELECT @PACKLIST_ID =[PACKLIST_ID]
                    ,@LINE_NO = [LINE_NO]
        FROM DELETED

        DELETE [dbo].[MyDataTable]
        WHERE [PACKLIST_ID]=@PACKLIST_ID AND [LINE_NO]=@LINE_NO
    END
 Else
    BEGIN
            --
            -- Table INSERTED is common to both the INSERT, UPDATE trigger
            --
            SELECT @PACKLIST_ID =[PACKLIST_ID]
                ,@LINE_NO = [LINE_NO]
                ,@SHIPPED_QTY =[SHIPPED_QTY]
                ,@CUST_ORDER_ID = [CUST_ORDER_ID]
            FROM INSERTED 

         if @Action = 'I'
            -- This is an Insert Record Action
            --
            BEGIN
                INSERT INTO [MyChildTable]
                    (([PACKLIST_ID]
                    ,[LINE_NO]
                    ,[STATUS]
                VALUES
                    (@PACKLIST_ID
                    ,@LINE_NO
                    ,'New Record'
                    )
            END
        else
            -- This is an Update Record Action
            --
            BEGIN
                UPDATE [MyChildTable]
                    SET [PACKLIST_ID] = @PACKLIST_ID
                          ,[LINE_NO] = @LINE_NO
                          ,[STATUS]='Update Record'
                WHERE [PACKLIST_ID]=@PACKLIST_ID AND [LINE_NO]=@LINE_NO
            END
    END   

9

Я вважаю, що вкладені ifs трохи заплутані:

Квартира краще, ніж вкладена [Дзен Пітона]

;)

DROP TRIGGER IF EXISTS AFTER_MYTABLE

GO

CREATE TRIGGER dbo.AFTER_MYTABLE ON dbo.MYTABLE AFTER INSERT, UPDATE, DELETE 

AS BEGIN 

    --- FILL THE BEGIN/END SECTION FOR YOUR NEEDS.

    SET NOCOUNT ON;

    IF EXISTS(SELECT * FROM INSERTED)  AND EXISTS(SELECT * FROM DELETED) 
        BEGIN PRINT 'UPDATE' END 
    ELSE IF EXISTS(SELECT * FROM INSERTED)  AND NOT EXISTS(SELECT * FROM DELETED) 
        BEGIN PRINT 'INSERT' END 
    ELSE IF    EXISTS(SELECT * FROM DELETED) AND NOT EXISTS(SELECT * FROM INSERTED)
        BEGIN PRINT 'DELETED' END
    ELSE BEGIN PRINT 'NOTHING CHANGED'; RETURN; END  -- NOTHING

END

9
Declare @Type varchar(50)='';
IF EXISTS (SELECT * FROM inserted) and  EXISTS (SELECT * FROM deleted)
BEGIN
    SELECT @Type = 'UPDATE'
END
ELSE IF EXISTS(SELECT * FROM inserted)
BEGIN
    SELECT @Type = 'INSERT'
END
ElSE IF EXISTS(SELECT * FROM deleted)
BEGIN
    SELECT @Type = 'DELETE'
END

5

Спробуйте це..

ALTER TRIGGER ImportacionesGS ON dbo.Compra 
    AFTER INSERT, UPDATE, DELETE
AS
BEGIN
  -- idCompra is PK
  DECLARE @vIdCompra_Ins INT,@vIdCompra_Del INT
  SELECT @vIdCompra_Ins=Inserted.idCompra FROM Inserted
  SELECT @vIdCompra_Del=Deleted.idCompra FROM Deleted
  IF (@vIdCompra_Ins IS NOT NULL AND @vIdCompra_Del IS NULL)  
  Begin
     -- Todo Insert
  End
  IF (@vIdCompra_Ins IS NOT NULL AND @vIdCompra_Del IS NOT NULL)
  Begin
     -- Todo Update
  End
  IF (@vIdCompra_Ins IS NULL AND @vIdCompra_Del IS NOT NULL)
  Begin
     -- Todo Delete
  End
END

4

в той час, як мені також подобається відповідь, опублікована @Alex, я пропоную цю варіацію для рішення @ Graham вище

для цього використовується виключно запис записів у таблицях INSERTED та UPDATED, на відміну від використання COLUMNS_UPDATED для першого тесту. Він також забезпечує полегшення програміста-параноїда, знаючи, що остання справа була розглянута ...

declare @action varchar(4)
    IF EXISTS (SELECT * FROM INSERTED)
        BEGIN
            IF EXISTS (SELECT * FROM DELETED) 
                SET @action = 'U'  -- update
            ELSE
                SET @action = 'I'  --insert
        END
    ELSE IF EXISTS (SELECT * FROM DELETED)
        SET @action = 'D'  -- delete
    else 
        set @action = 'noop' --no records affected
--print @action

ви отримаєте NOOP із таким твердженням:

update tbl1 set col1='cat' where 1=2

Здається, що перший з ENDвідступом неправильно! (викликає сумніви, де BEGINзакрито перше )
С.Серпоошан

інше, якщо і остаточно, містять окремі заяви. початок і кінець справді непотрібні, оскільки IF / Else - це єдине твердження. Я виправив відступ. Дякую за допомогу.
Greg

3

Це може бути більш швидким способом:

DECLARE @action char(1)

IF COLUMNS_UPDATED() > 0 -- insert or update
BEGIN
    IF EXISTS (SELECT * FROM DELETED) -- update
        SET @action = 'U'
    ELSE
        SET @action = 'I'
    END
ELSE -- delete
    SET @action = 'D'

4
Цей спосіб не працює для таблиць з великою кількістю стовпців, оскільки column_update () повертає величезний varbinary. Тож "> 0" не вдається, оскільки значення за замовчуванням для внутрішнього збереженого числа значно менше значення, поверненого з столбцов_обновленных ()
Грем

3

Потенційна проблема двох запропонованих рішень полягає в тому, що залежно від того, як вони написані, запит оновлення може оновлювати нульові записи, а запит на вставлення може вставляти нульові записи. У цих випадках набори вставлених та видалених записів будуть порожніми. У багатьох випадках, якщо і вкладені, і видалені набори записів порожні, ви можете просто вийти з тригера, не роблячи нічого.


2

Я знайшов невелику помилку в іншому класному рішенні Grahams:

Це повинно бути, якщо COLUMNS_UPDATED () < > 0 - вставити або оновити
замість> 0, ймовірно, тому, що верхній біт інтерпретується як SIGNED integer bit bit ... (?). Отже, загалом:

DECLARE @action CHAR(8)  
IF COLUMNS_UPDATED() <> 0 -- delete or update?
BEGIN     
  IF EXISTS (SELECT * FROM deleted) -- updated cols + old rows means action=update       
    SET @action = 'UPDATE'     
  ELSE
    SET @action = 'INSERT' -- updated columns and nothing deleted means action=insert
END 
ELSE -- delete     
BEGIN
  SET @action = 'DELETE'
END

1

Це робить фокус для мене:

declare @action_type int;
select @action_type = case
                       when i.id is not null and d.id is     null then 1 -- insert
                       when i.id is not null and d.id is not null then 2 -- update
                       when i.id is     null and d.id is not null then 3 -- delete
                     end
  from      inserted i
  full join deleted  d on d.id = i.id

Оскільки не всі стовпці можуть бути оновлені одночасно, ви можете перевірити, чи оновлюється певний стовпець чимось таким:

IF UPDATE([column_name])

Проблема з цим рішенням полягає в тому, що ви повинні знати назву стовпця. Деякі з інших розроблені таким чином, що ви можете просто скопіювати пасту з бібліотеки фрагментів. Невеликий сенс, але все, що враховується, загальне рішення краще, ніж конкретне рішення. ІМХО.
greg

1
declare @insCount int
declare @delCount int
declare @action char(1)

select @insCount = count(*) from INSERTED
select @delCount = count(*) from DELETED

    if(@insCount > 0 or @delCount > 0)--if something was actually affected, otherwise do nothing
    Begin
        if(@insCount = @delCount)
            set @action = 'U'--is update
        else if(@insCount > 0)
            set @action = 'I' --is insert
        else
            set @action = 'D' --is delete

        --do stuff here
    End

1
Я б не використовував COUNT (*) з міркувань продуктивності - для цього потрібно сканувати всю таблицю. Я б замість цього встановив прапор, використовуючи IF EXISTS (SELECT * FROM INSERTED), той самий для DELETED. Я знаю, що нормально впливає лише пара рядків, але чому гальмувати систему.
Endrju

Я збирався розмістити щось дуже схоже на рішення. Це трохи слово, але дуже читабельно. Справедливий компроміс. Мені також подобається рішення Грамса вище.
greg

1

Мені подобаються рішення, які є "елегантною інформатикою". Моє рішення тут потрапляє на [вставлені] та [видалені] псевдотаблиці один раз у кожному, щоб отримати їхні статуси, і результат додає у бітову відображену змінну. Тоді кожну можливу комбінацію INSERT, UPDATE та DELETE можна легко перевірити протягом тригера за допомогою ефективних бінарних оцінок (за винятком малоймовірних комбінацій INSERT або DELETE).

Це робить припущення, що не має значення, яким був оператор DML, якщо жодні рядки не були змінені (що повинно задовольнити переважну більшість випадків). Тож поки воно не таке повне, як рішення Романа Пекара, воно є більш ефективним.

При такому підході ми маємо можливість одного тригера "ЗА ВСТАВКИ, ОНОВЛЕННЯ, УДАЛЕННЯ" на кожну таблицю, що дає нам A) повний контроль над порядком дії та б) одна реалізація коду за дію, що застосовується до кількох дій. (Очевидно, що кожна модель реалізації має свої плюси і мінуси; вам потрібно буде оцінювати свої системи індивідуально для того, що дійсно найкраще працює.)

Зауважте, що оператори "існує (виберіть * із« вставленого / видаленого »)" дуже ефективні, оскільки немає доступу до диска ( https://social.msdn.microsoft.com/Forums/en-US/01744422-23fe-42f6 -9ab0-a255cdf2904a ).

use tempdb
;
create table dbo.TrigAction (asdf int)
;
GO
create trigger dbo.TrigActionTrig
on dbo.TrigAction
for INSERT, UPDATE, DELETE
as
declare @Action tinyint
;
-- Create bit map in @Action using bitwise OR "|"
set @Action = (-- 1: INSERT, 2: DELETE, 3: UPDATE, 0: No Rows Modified 
  (select case when exists (select * from inserted) then 1 else 0 end)
| (select case when exists (select * from deleted ) then 2 else 0 end))
;
-- 21 <- Binary bit values
-- 00 -> No Rows Modified
-- 01 -> INSERT -- INSERT and UPDATE have the 1 bit set
-- 11 -> UPDATE <
-- 10 -> DELETE -- DELETE and UPDATE have the 2 bit set

raiserror(N'@Action = %d', 10, 1, @Action) with nowait
;
if (@Action = 0) raiserror(N'No Data Modified.', 10, 1) with nowait
;
-- do things for INSERT only
if (@Action = 1) raiserror(N'Only for INSERT.', 10, 1) with nowait
;
-- do things for UPDATE only
if (@Action = 3) raiserror(N'Only for UPDATE.', 10, 1) with nowait
;
-- do things for DELETE only
if (@Action = 2) raiserror(N'Only for DELETE.', 10, 1) with nowait
;
-- do things for INSERT or UPDATE
if (@Action & 1 = 1) raiserror(N'For INSERT or UPDATE.', 10, 1) with nowait
;
-- do things for UPDATE or DELETE
if (@Action & 2 = 2) raiserror(N'For UPDATE or DELETE.', 10, 1) with nowait
;
-- do things for INSERT or DELETE (unlikely)
if (@Action in (1,2)) raiserror(N'For INSERT or DELETE.', 10, 1) with nowait
-- if already "return" on @Action = 0, then use @Action < 3 for INSERT or DELETE
;
GO

set nocount on;

raiserror(N'
INSERT 0...', 10, 1) with nowait;
insert dbo.TrigAction (asdf) select top 0 object_id from sys.objects;

raiserror(N'
INSERT 3...', 10, 1) with nowait;
insert dbo.TrigAction (asdf) select top 3 object_id from sys.objects;

raiserror(N'
UPDATE 0...', 10, 1) with nowait;
update t set asdf = asdf /1 from dbo.TrigAction t where asdf <> asdf;

raiserror(N'
UPDATE 3...', 10, 1) with nowait;
update t set asdf = asdf /1 from dbo.TrigAction t;

raiserror(N'
DELETE 0...', 10, 1) with nowait;
delete t from dbo.TrigAction t where asdf < 0;

raiserror(N'
DELETE 3...', 10, 1) with nowait;
delete t from dbo.TrigAction t;
GO

drop table dbo.TrigAction
;
GO

Дякую за таке рішення, яке сприймає в моєму контексті. Чи рекомендуєте ви спосіб оновлення стовпця LastUpdated оновленого / вставленого рядка? Чи рекомендуєте ви також спосіб зберігання в іншій таблиці ідентифікатора видаленого рядка (може бути складений ключ)?
Себастьян

0

Швидке рішення MySQL

До речі: я використовую PDO MySQL.

(1) У таблиці автоматичного збільшення просто отримайте найвище значення (моє ім'я стовпця = ідентифікатор) з посиленого стовпця, коли кожен сценарій запускається першим:

$select = "
    SELECT  MAX(id) AS maxid
    FROM    [tablename]
    LIMIT   1
";

(2) Запустіть запит MySQL так, як ви цього робили, і виведіть результат на ціле число, наприклад:

$iMaxId = (int) $result[0]->maxid;

(3) Після запиту "ВСТАВИТИ У ... НА ДУПЛІКАТИ КЛЮЧОВОГО ОНОВЛЕННЯ" отримайте останній вставлений ідентифікатор, який ви бажаєте, наприклад:

$iLastInsertId = (int) $db->lastInsertId();

(4) Порівняйте та реагуйте: Якщо lastInsertId вище, ніж найвищий у таблиці, це, ймовірно, ВСТАВКА, правда? І навпаки.

if ($iLastInsertId > $iMaxObjektId) {
    // IT'S AN INSERT
}
else {
    // IT'S AN UPDATE
}

Я знаю, що це швидко і, можливо, брудно. І це старий пост. Але, ей, я довго шукав рішення, і, можливо, хтось вважає мій шлях дещо корисним. Всього найкращого!


0

просто простий спосіб

CREATE TRIGGER [dbo].[WO_EXECUTION_TRIU_RECORD] ON [dbo].[WO_EXECUTION]
WITH EXECUTE AS CALLER
FOR INSERT, UPDATE
AS
BEGIN  

  select @vars = [column] from inserted 
  IF UPDATE([column]) BEGIN
    -- do update action base on @vars 
  END ELSE BEGIN
    -- do insert action base on @vars 
  END

END 

Згідно з моїм IDE SSMS, ваш синтаксис не відповідає правильності того, як ви переводите свою логіку в блоки IF BEGIN - END ELSE BEGIN - END.
Ерутан409

0

У першому сценарії я вважав, що у вашій таблиці є стовпець "ІДЕНТИМЕНТ"

CREATE TRIGGER [dbo].[insupddel_yourTable] ON [yourTable]
FOR INSERT, UPDATE, DELETE
AS
IF @@ROWCOUNT = 0 return
SET NOCOUNT ON;
DECLARE @action nvarchar(10)
SELECT @action = CASE WHEN COUNT(i.Id) > COUNT(d.Id) THEN 'inserted'
                      WHEN COUNT(i.Id) < COUNT(d.Id) THEN 'deleted' ELSE 'updated' END
FROM inserted i FULL JOIN deleted d ON i.Id = d.Id

У другому сценарії не потрібно використовувати стовпець IDENTITTY

CREATE TRIGGER [dbo].[insupddel_yourTable] ON [yourTable]
FOR INSERT, UPDATE, DELETE
AS
IF @@ROWCOUNT = 0 return
SET NOCOUNT ON;
DECLARE @action nvarchar(10),
        @insCount int = (SELECT COUNT(*) FROM inserted),
        @delCount int = (SELECT COUNT(*) FROM deleted)
SELECT @action = CASE WHEN @insCount > @delCount THEN 'inserted'
                      WHEN @insCount < @delCount THEN 'deleted' ELSE 'updated' END

У мене ж питання, якийсь може мені допомогти. Дивіться наступне посилання stackoverflow.com/questions/26043106/…
Ramesh S

0
DECLARE @INSERTEDCOUNT INT,
        @DELETEDCOUNT INT

SELECT @INSERTEDCOUNT = COUNT([YourColumnName]) FROM inserted

SELECT @DELETEDCOUNT = COUNT([YourColumnName]) FROM deleted

ЯКЩО його оновлення

 @INSERTEDCOUNT = 1
 @DELETEDCOUNT = 1

якщо його введення

 @INSERTEDCOUNT = 1
 @DELETEDCOUNT = 0

0

Я використовував ці exists (select * from inserted/deleted)запити давно, але його все ще недостатньо для порожніх операцій CRUD (коли немає записів insertedі deletedтаблиць). Отже, трохи вивчивши цю тему, я знайшов більш точне рішення:

declare
    @columns_count int = ?? -- number of columns in the table,
    @columns_updated_count int = 0

-- this is kind of long way to get number of actually updated columns
-- from columns_updated() mask, it's better to create helper table
-- or at least function in the real system
with cte_columns as (
    select @columns_count as n
    union all
    select n - 1 from cte_columns where n > 1
), cte_bitmasks as (
    select
        n,
        (n - 1) / 8 + 1 as byte_number,
        power(2, (n - 1) % 8) as bit_mask
    from cte_columns
)
select
    @columns_updated_count = count(*)
from cte_bitmasks as c
where
    convert(varbinary(1), substring(@columns_updated_mask, c.byte_number, 1)) & c.bit_mask > 0

-- actual check
if exists (select * from inserted)
    if exists (select * from deleted)
        select @operation = 'U'
    else
        select @operation = 'I'
else if exists (select * from deleted)
    select @operation = 'D'
else if @columns_updated_count = @columns_count
    select @operation = 'I'
else if @columns_updated_count > 0
    select @operation = 'U'
else
    select @operation = 'D'

Можна також використовувати, columns_updated() & power(2, column_id - 1) > 0щоб побачити, чи стовпчик оновлюється, але це не безпечно для таблиць з великою кількістю стовпців. Я використав трохи складний спосіб розрахунку (див. Корисну статтю нижче).

Крім того, цей підхід все одно неправильно класифікує деякі оновлення як вставки (якщо оновлення впливає на кожен стовпець таблиці), і, ймовірно, він класифікує вставки, де в якості видалених вставляються лише значення за замовчуванням, але вони є королем рідкісних операцій (у оренди в моїй системі вони є). Крім того, на даний момент я не знаю, як покращити це рішення.


0
declare @result as smallint
declare @delete as smallint = 2
declare @insert as smallint = 4
declare @update as smallint = 6
SELECT @result = POWER(2*(SELECT count(*) from deleted),1) + POWER(2*(SELECT 
     count(*) from inserted),2)

if (@result & @update = @update) 
BEGIN
  print 'update'
  SET @result=0
END
if (@result & @delete = @delete)
  print 'delete'
if (@result & @insert = @insert)
  print 'insert'

0

я роблю це:

select isnull((select top 1 1 from inserted t1),0) + isnull((select top 1 2 from deleted t1),0)

1 -> вставка

2 -> видалити

3 -> оновлення

set @i = isnull((select top 1 1 from inserted t1),0) + isnull((select top 1 2 from deleted t1),0)
--select @i

declare @action varchar(1) = case @i when 1 then 'I' when 2 then 'D' when 3 then 'U' end
--select @action


select @action c1,* from inserted t1 where @i in (1,3) union all
select @action c1,* from deleted t1 where @i in (2)

0
DECLARE @ActionType CHAR(6);
SELECT  @ActionType = COALESCE(CASE WHEN EXISTS(SELECT * FROM INSERTED)
                                     AND EXISTS(SELECT * FROM DELETED)  THEN 'UPDATE' END,
                               CASE WHEN EXISTS(SELECT * FROM DELETED)  THEN 'DELETE' END,
                               CASE WHEN EXISTS(SELECT * FROM INSERTED) THEN 'INSERT' END);
PRINT   @ActionType;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.