Inserisci aggiornamento trigger come determinare se inserire o aggiornare


162

Ho bisogno di scrivere un trigger Inserisci, Aggiorna sulla tabella A che eliminerà tutte le righe dalla tabella B la cui colonna (diciamo Desc) ha valori come il valore inserito / aggiornato nella colonna della tabella A (diciamo Col1). Come potrei andare in giro a scriverlo in modo da poter gestire sia i casi di aggiornamento che quelli di inserimento. Come determinerei se il trigger viene eseguito per un aggiornamento o un inserimento.

Risposte:


167

I trigger hanno speciali INSERTEDe DELETEDtabelle per tracciare i dati "prima" e "dopo". Quindi puoi usare qualcosa di simile IF EXISTS (SELECT * FROM DELETED)per rilevare un aggiornamento. DELETEDNell'aggiornamento sono presenti solo righe , ma sono sempre presenti righe INSERTED.

Cerca "inserito" in CREATE TRIGGER .

Modifica, 23 nov 2011

Dopo il commento, questa risposta è solo per INSERTEDe si UPDATEDinnesca.
Ovviamente, i trigger DELETE non possono avere "sempre righe INSERTED" come ho detto sopra


Guarda la risposta di @ MikeTeeVee di seguito per una risposta completa. Questo è incompleto.
Lorenz Meyer,

1
La domanda originale di @LorenzMeyer non ne ha bisogno. Ho anche ESISTE (SELEZIONA * DA ELIMINATO). Non so perché pensi che non sia completo ...
gbn

Ciò a cui @LorenzMeyer può anche riferirsi è la frase " Hai solo righe in DELETED al momento dell'aggiornamento, ma ci sono sempre righe in INSERTED. " Questo non è sempre vero perché ci sono volte in cui viene chiamato il trigger Update / Insert e INSERTED è vuoto. Nella mia risposta spiego come ciò potrebbe essere causato dal Predicato eliminando qualsiasi dato dal cambiamento. In questo caso, il trigger viene comunque chiamato per il tentativo DML, ma le tabelle DELETED e INSERTED sono vuote. Questo perché SQL tiene ancora conto delle volte in cui si desidera registrare ogni tentativo DML (anche quando non alterano alcun dato).
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
Mi piace scrivere SELEZIONA 1 DALL'INSERITO anche se penso che segnali l'intento più chiaramente, ma sarei deluso dai programmatori MSSQL se questo fa la differenza in questo contesto ...
Lukáš Lánský

26
IF EXISTS (SELECT * ...) e IF EXISTS (SELECT 1) ... hanno esattamente le stesse prestazioni. La riga non viene letta né recuperata. In effetti puoi anche usare SE ESISTE (SELEZIONA 1/0 ...) e funzionerà comunque e non causerà la divisione per zero errori.
Endrju,

1
Stavo creando trigger separati per l'inserimento, l'aggiornamento e l'eliminazione. Ora è fantastico sapere che possono essere combinati!
UJS

2
Se qualcuno scrive una query per INSERIRE ed ELIMINARE due righe diverse (inserire una nuova riga ed eliminare un'altra riga nello stesso script), è possibile che il trigger impostato nel modo sopra lo identifichi effettivamente come un AGGIORNAMENTO (anche se l'intento non è effettivamente un aggiornamento) a causa della presenza di dati nelle tabelle sql INSERTED / DELETED?
Mche

87

Molti di questi suggerimenti non tengono conto se si esegue un'istruzione di eliminazione che non elimina nulla.
Supponi di provare a eliminare dove un ID equivale a un valore che non esiste nella tabella.
Il trigger viene ancora chiamato ma non c'è nulla nelle tabelle Eliminate o Inserite.

Usa questo per essere sicuro:

--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)

Un ringraziamento speciale a @KenDog e @Net_Prog per le loro risposte.
L'ho costruito dai loro script.


3
Questo è il premio, gestendo la cancellazione inesistente. Buon lavoro!
Andrew Wolfe,

6
Potremmo anche avere un AGGIORNAMENTO che non ha interessato nessuna riga (o addirittura un INSERT).
Razvan Socol,

@AndrewWolfe? Cosa stai dicendo? La domanda afferma specificamente che "Ho bisogno di scrivere un trigger Insert, Update sulla tabella A" . Niente sui trigger DELETE.
ypercubeᵀᴹ

@ ypercubeᵀᴹ scusate, circa l'80% dei miei trigger copre tutti e tre i tempi.
Andrew Wolfe,

18

Sto usando quanto segue, inoltre rileva correttamente le istruzioni di eliminazione che non eliminano nulla:

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
questo però rileva erroneamente istruzioni che non inseriscono nulla o non aggiornano nulla.
Roman Pekar,

11

Dopo molte ricerche non sono riuscito a trovare un esempio esatto di un singolo trigger di SQL Server che gestisca tutte (3) tre condizioni delle azioni del trigger INSERT, UPDATE e DELETE. Alla fine ho trovato una riga di testo che parlava del fatto che quando si verifica un DELETE o un AGGIORNAMENTO, la tabella DELETED comune conterrà un record per queste due azioni. Sulla base di tali informazioni, ho quindi creato una piccola routine di azione che determina perché il trigger è stato attivato. Questo tipo di interfaccia è talvolta necessario quando è presente una configurazione comune e un'azione specifica su un trigger INSERT vs. UPDATE. In questi casi, creare un trigger separato per UPDATE e INSERT diventerebbe un problema di manutenzione. (cioè entrambi i trigger sono stati aggiornati correttamente per la necessaria correzione dell'algoritmo di dati comuni?)

A tal fine, vorrei fornire il seguente frammento di codice evento multi-trigger per la gestione di INSERT, UPDATE, DELETE in un trigger per un 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

Credo che il nidificato sia un po 'confuso e:

Flat è meglio di nidificato [The Zen of Python]

;)

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

Prova questo..

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

mentre mi piace anche la risposta pubblicata da @Alex, offro questa variazione alla soluzione di @ Graham sopra

questo utilizza esclusivamente l'esistenza di record nelle tabelle INSERTED e UPDATED, anziché utilizzare COLUMNS_UPDATED per il primo test. Fornisce anche il sollievo programmatore paranoico sapendo che il caso finale è stato considerato ...

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

otterrai NOOP con una dichiarazione simile alla seguente:

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

Sembra che il primo ENDsia rientrato a torto! (causando la questione di dove BEGINsia chiuso il primo )
S.Serpooshan,

l'altro if e final else contengono singole istruzioni. l'inizio e la fine sono davvero inutili poiché IF / Else è una singola istruzione. Ho corretto il rientro. Grazie per l'aiuto.
Greg

3

Questo potrebbe essere un modo più veloce:

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
In questo modo non funziona per le tabelle con un numero elevato di colonne in quanto colonne_update () restituisce un varbinary che è enorme. Quindi lo "> 0" fallisce perché lo 0 è impostato per default su un numero memorizzato internamente molto più piccolo del valore restituito da column_updated ()
Graham

3

Un potenziale problema con le due soluzioni offerte è che, a seconda della modalità di scrittura, una query di aggiornamento può aggiornare zero record e una query di inserimento può inserire zero record. In questi casi, i recordset inseriti ed eliminati saranno vuoti. In molti casi, se entrambi i recordset inseriti ed eliminati sono vuoti, potresti voler uscire dal trigger senza fare nulla.


2

Ho trovato un piccolo errore nella soluzione Grahams altrimenti interessante:

Dovrebbe essere SE COLUMNS_UPDATED () < > 0 - inserisci o aggiorna
invece di> 0 probabilmente perché il bit superiore viene interpretato come bit di segno intero SIGNED ... (?). Quindi in totale:

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

Questo fa il trucco per me:

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

Poiché non tutte le colonne possono essere aggiornate contemporaneamente, puoi verificare se una determinata colonna viene aggiornata da qualcosa del genere:

IF UPDATE([column_name])

Una sfida con questa soluzione è che devi conoscere il nome di una colonna. Alcuni altri sono progettati in modo tale da poter semplicemente copiare e incollare da una libreria di frammenti. Piccolo punto, ma tutto sommato, una soluzione generica è migliore di una soluzione specifica per caso. A PARER MIO.
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
Non userei COUNT (*) per motivi di prestazioni - deve scansionare l'intera tabella. Vorrei invece impostare una bandiera utilizzando SE ESISTE (SELEZIONA * DA INSERITO), lo stesso per ELIMINATO. So che normalmente sono interessate solo un paio di file, ma perché rallentare il sistema.
Endrju,

Stavo per pubblicare qualcosa di molto simile come soluzione. È un po 'prolisso, ma molto leggibile. Equo compromesso. Mi piace anche la soluzione Grahms sopra.
Greg

1

Mi piacciono le soluzioni "informatiche eleganti". La mia soluzione qui colpisce gli pseudotable [inseriti] e [eliminati] una volta ciascuno per ottenere i loro stati e inserisce il risultato in una variabile bit mappata. Quindi ogni possibile combinazione di INSERT, UPDATE e DELETE può essere prontamente testata in tutto il trigger con valutazioni binarie efficienti (ad eccezione della combinazione INSERT o DELETE improbabile).

Presuppone che non importa quale fosse l'istruzione DML se nessuna riga è stata modificata (il che dovrebbe soddisfare la stragrande maggioranza dei casi). Quindi, sebbene non sia completo come la soluzione di Roman Pekar, è più efficiente.

Con questo approccio, abbiamo la possibilità di un trigger "FOR INSERT, UPDATE, DELETE" per tabella, dandoci A) controllo completo sull'ordine delle azioni eb) un'implementazione del codice per ogni azione applicabile a più azioni. (Ovviamente, ogni modello di implementazione ha i suoi pro e contro; dovrai valutare i tuoi sistemi individualmente per ciò che funziona davvero meglio.)

Si noti che le istruzioni "esiste (selezionare * da« inserito / cancellato »)" sono molto efficienti poiché non esiste accesso al disco ( 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

Grazie per questa soluzione che si inserisce nel mio contesto. Consiglieresti un modo per aggiornare la colonna LastUpdated della riga aggiornata / inserita? Consiglieresti anche un modo per memorizzare su un'altra tabella l'ID della riga eliminata (può essere una chiave composta)?
Sébastien,

0

Soluzione rapida MySQL

A proposito: sto usando MySQL DOP.

(1) In una tabella di incremento automatico basta ottenere il valore più alto (nome colonna = id) dalla colonna incrementata una volta che ogni script viene eseguito per primo:

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

(2) Esegui la query MySQL come faresti normalmente e lancia il risultato in numero intero, ad esempio:

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

(3) Dopo la query "INSERT INTO ... ON DUPLICATE KEY UPDATE" ottieni l'ultimo ID inserito nel modo che preferisci, ad esempio:

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

(4) Confronta e reagisci: se lastInsertId è più alto del più alto nella tabella, probabilmente è un INSERT, giusto? E viceversa.

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

So che è veloce e forse sporco. Ed è un vecchio post. Ma, ehi, stavo cercando una soluzione da molto tempo, e forse qualcuno trova comunque la mia strada in qualche modo utile. Ti auguro il meglio!


0

solo un modo semplice

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 

Secondo il mio IDE SSMS, la tua sintassi non è corretta con il modo in cui stai avvolgendo la logica nei blocchi IF BEGIN - END ELSE BEGIN - END.
Erutan409,

0

Nel primo scenario supponevo che la tua tabella avesse la colonna IDENTITY

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

Nel secondo scenario non è necessario utilizzare la colonna 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

Ho lo stesso problema che qualcuno mi può aiutare. Vedere il seguente link stackoverflow.com/questions/26043106/…
Ramesh S

0
DECLARE @INSERTEDCOUNT INT,
        @DELETEDCOUNT INT

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

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

SE il suo aggiornamento

 @INSERTEDCOUNT = 1
 @DELETEDCOUNT = 1

se il suo inserimento

 @INSERTEDCOUNT = 1
 @DELETEDCOUNT = 0

0

Ho usato quelle exists (select * from inserted/deleted)query per molto tempo, ma non è ancora sufficiente per le operazioni CRUD vuote (quando non ci sono record insertede deletedtabelle). Quindi dopo aver studiato un po 'questo argomento ho trovato una soluzione più precisa:

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'

È anche possibile utilizzare columns_updated() & power(2, column_id - 1) > 0per vedere se la colonna è aggiornata, ma non è sicuro per le tabelle con un numero elevato di colonne. Ho usato un modo un po 'complesso di calcolo (vedi l'articolo utile sotto).

Inoltre, questo approccio classificherà ancora erroneamente alcuni aggiornamenti come inserti (se ogni colonna della tabella è interessata dall'aggiornamento), e probabilmente classificherà gli inserti in cui vengono inseriti solo valori predefiniti come eliminazioni, ma questi sono re di operazioni rare (at contratto di locazione nel mio sistema sono). Oltre a ciò, al momento non so come migliorare questa soluzione.


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

lo faccio:

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

1 -> inserisci

2 -> elimina

3 -> aggiornamento

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;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.