Insert Güncelleme tetikleyici, insert veya güncelleme olup olmadığını belirleme


162

Ben bir sütun (Desc demek) Tablo A sütununda eklenen / güncellenen değeri gibi değerleri olan tablo B tüm satırları siler A Tablo üzerinde bir Ekle, Güncelleme Tetikleyici yazmak gerekir. Hem Güncelle hem de Ekle vakalarını işleyebilmem için nasıl yazacağım. Bir güncelleme veya ekleme için tetikleyicinin yürütülüp yürütülmediğini nasıl belirleyebilirim.

Yanıtlar:


167

Tetikleyiciler "önce" ve "sonra" verilerini izlemek için özel INSERTEDve DELETEDtablolara sahiptir. Böylece IF EXISTS (SELECT * FROM DELETED)bir güncellemeyi algılamak gibi bir şey kullanabilirsiniz . DELETEDGüncellemede yalnızca satırlarınız var , ancak her zaman satırlar varINSERTED .

CREATE TRIGGER içinde "eklenmiş" ifadesini arayın .

Düzenle, 23 Kas 2011

Yorumdan sonra, bu cevap sadece içindir INSERTEDve UPDATEDtetikler.
Açıkçası, DELETE tetikleyicilerinin INSERTEDyukarıda söylediğim gibi "her zaman satırları" olamaz


Tam bir cevap için @ MikeTeeVee'nin cevabına bakınız. Bu eksik.
Lorenz Meyer

1
@LorenzMeyer orijinal sorunun buna ihtiyacı yoktur. Ayrıca VAR var (SİLİNDEN * SEÇ). Neden tam olmadığını düşündüğünüzden emin değilim ...
19:00

Ne @LorenzMeyer da atıfta olabilir ifadedir " Yalnızca güncelleme üzerinde SİLİNMİŞ satırları var, ama orada her zaman satır eklenir içinde. " Bu değil , her zaman Güncelleme / Ekleme Tetik aradı ve yerleştirildiğinde olduğu zamanlar vardır, çünkü gerçek boş. Cevabımda bunun Predicate'in herhangi bir verinin değişmesini ortadan kaldırmasının neden olabileceğini açıklıyorum. Bu durumda, DML denemesi için Tetikleyici çağrılır, ancak DELETED ve INSERTED tabloları boştur. Bunun nedeni, SQL'in her bir DML girişimini günlüğe kaydetmek istediğiniz zamanları (herhangi bir veri değiştirmemiş olsalar bile) hesaba katmasıdır.
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
Ben de daha net niyet sinyalleri düşünüyorum düşünüyorum da INSERTED SEÇ 1 yazmak istiyorum, ama bu bağlamda herhangi bir fark yaparsa MSSQL programcılar tarafından disapointed olurdu ...
Lukáš Lánský

26
EĞER VARSA (SEÇ * *) ve EĞER VAR (SEÇ 1) ... tam olarak aynı performansa sahiptir. Satır hiç okunmaz veya getirilmez. Aslında IF EXISTS'i (SEÇ 1/0 ...) da kullanabilirsiniz ve yine de çalışır ve sıfır hata ile bölünmeye neden olmaz.
Endrju

1
Eklemek, güncellemek ve silmek için ayrı Tetikleyiciler oluşturuyordum.
UJS

2
Birisi iki farklı satırı INSERT ve DELETE yazarsa (yeni satır ekleyin ve aynı komut dosyasında başka bir satır silin), yukarıdaki şekilde ayarlanan tetikleyicinin bunu gerçekten bir GÜNCELLEME olarak tanımlaması mümkün mü (amaç aslında bir güncelleme değildir) INSERTED / DELETED sql tablolarında veri olması nedeniyle?
mche

87

Hiçbir şeyi silen bir delete deyimi çalıştırırsanız bu önerilerin çoğu dikkate alınmaz.
Diyelim ki bir kimlik tabloda olmayan bazı değerlere eşittir.
Tetikleyiciniz hala çağrılıyor, ancak Silinmiş veya Eklenen tablolarda hiçbir şey yok.

Güvende olmak için bunu kullanın:

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

Cevapları için @KenDog ve @Net_Prog'a özel teşekkürler.
Bunu senaryolarından yaptım.


3
Bu, var olmayanları silme ödülünü alır. İyi iş!
Andrew Wolfe

6
Ayrıca hiçbir satırı (hatta bir INSERT) etkilemeyen bir GÜNCELLEMİZ olabilir.
Razvan Socol

@ AndrewWolfe? Ne diyorsun? Soru özellikle "Tablo A'ya bir Güncelleştirme Tetikleyicisi yazmam gerekiyor" yazıyor . DELETE tetikleyicileri hakkında hiçbir şey yok.
ypercubeᵀᴹ

@ ypercubeᵀᴹ üzgünüm, tetikleyicilerimin yaklaşık% 80'i üç zamanlamayı da kapsıyor.
Andrew Wolfe

18

Aşağıdaki kullanıyorum, aynı zamanda hiçbir şey silmez silmek ifadeleri doğru tespit:

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
bu yanlış bir şey ekleyen veya hiçbir şey güncelleme deyimleri yanlış algılar.
Roman Pekar

11

Bir çok aramadan sonra INSERT, UPDATE ve DELETE tetikleyici eylemlerinin tüm (3) üç koşulunu işleyen tek bir SQL Server tetikleyicisinin tam bir örneğini bulamadım. Sonunda bir DELETE veya UPDATE oluştuğunda, ortak DELETED tablosunun bu iki eylem için bir kayıt içereceği gerçeğinden bahseden bir metin satırı buldum. Bu bilgilere dayanarak, tetikleyicinin neden etkinleştirildiğini belirleyen küçük bir Eylem rutini oluşturdum. Bu tip bir arayüz, INSERT ve UPDATE tetikleyicisinde hem ortak bir yapılandırma hem de belirli bir eylem olduğunda bazen gereklidir. Bu durumlarda, UPDATE ve INSERT için ayrı bir tetikleyici oluşturmak bakım sorunu haline gelir. (yani her iki tetikleyici de gerekli ortak veri algoritması düzeltmesi için doğru şekilde güncellendi mi?)

Bu amaçla, bir SQL Server için bir tetikleyicide INSERT, UPDATE, DELETE işlemek için aşağıdaki çoklu tetikleyici olay kodu snippet'ini vermek istiyorum.

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

Eğer biraz kafa karıştırıcı ifs iç içe inanıyorum ve:

Düz iç içe geçmişten daha iyidir [Python'un Zen'i]

;)

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

Bunu dene..

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 tarafından gönderilen yanıtı da beğenirken, yukarıdaki @ Graham'ın çözümüne bu varyasyonu sunuyoruz

bu, ilk test için COLUMNS_UPDATED kullanılması yerine INSERTED ve UPDATED tablolarında yalnızca kayıt varlığını kullanır. Ayrıca, son davanın dikkate alındığını bilen paranoyak programcı rahatlığı sağlar ...

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

aşağıdaki gibi bir ifadeyle NOOP alacaksınız:

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

Birincisi ENDyanlış girintili görünüyor ! (ilkinin nerede BEGINkapatıldığı sorusuna neden oluyor )
S.Serpooshan

diğer if ve final başka tek ifadeler içeriyorsa. IF / Else tek bir ifade olduğu için başlangıç ​​ve bitiş gerçekten gereksizdir. Girintiyi düzelttim. Yardım için teşekkürler.
greg

3

Bu daha hızlı bir yol olabilir:

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_updated () çok büyük bir varbinary döndürdüğünden, çok sayıda sütuna sahip tablolar için bu şekilde çalışmaz. "> 0" dan dönen değerden çok daha küçük bir iç saklanan sayıya çünkü 0 varsayılan başarısız Yani () columns_updated
Graham

3

Sunulan iki çözümle ilgili olası bir sorun, nasıl yazıldıklarına bağlı olarak, bir güncelleştirme sorgusunun sıfır kayıtları güncelleyebilmesi ve bir ekleme sorgusunun sıfır kayıtları ekleyebilmesidir. Bu durumlarda, Eklenen ve Silinen kayıt kümeleri boş olacaktır. Çoğu durumda, hem Takılı hem de Silinen kayıt kümeleri boşsa, tetikleyiciden hiçbir şey yapmadan çıkmak isteyebilirsiniz.


2

Grahams küçük bir hata buldum aksi takdirde serin bir çözüm:

Büyük olasılıkla üst bit SIGNED tamsayı işaret biti olarak yorumlanır çünkü (> < > 0 -> 0
yerine ekleme veya güncelleme EĞER olmalıdır . (?). Yani toplamda:

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

Bu benim için hile yapar:

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

Tüm sütunlar aynı anda güncellenemediğinden, belirli bir sütunun aşağıdaki gibi bir şeyle güncellenip güncellenmediğini kontrol edebilirsiniz:

IF UPDATE([column_name])

Bu çözümle ilgili bir zorluk, bir sütun adı bilmeniz gerektiğidir. Diğerlerinden bazıları pasajı bir pasaj kütüphanesinden kopyalayabileceğiniz şekilde tasarlanmıştır. Küçük nokta, ancak her şey düşünüldüğünde, genel bir çözüm, duruma özgü bir çözümden daha iyidir. BENİM NACİZANE FİKRİME GÖRE.
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
Performans nedenleriyle COUNT (*) kullanmam - tüm tabloyu taraması gerekiyor. Bunun yerine, silinmiş için aynı IF EXISTS (SELECT * FROM INSERTED) kullanarak bir bayrak ayarlamak istiyorum. Normalde etkilenen sadece birkaç satır olduğunu biliyorum, ancak sistemi neden yavaşlatıyor?
Endrju

Çözüm olarak çok benzer bir şey yayınlamak üzereydim. Onun biraz garip, ama çok okunabilir. Adil takas. Yukarıdaki Grahms Solution'ı da beğendim.
greg

1

"Bilgisayar bilimi zarif" çözümlerini severim. Buradaki çözümüm, durumlarını almak için her birinde [eklenen] ve [silinen] sözde tablolara vurur ve sonucu biraz eşlenen bir değişkene koyar. Daha sonra, INSERT, UPDATE ve DELETE'nin olası her kombinasyonu etkin ikili değerlendirmelerle (olası olmayan INSERT veya DELETE kombinasyonu hariç) tetik boyunca kolayca test edilebilir.

Hiçbir satır değiştirilmediyse (vakaların büyük çoğunluğunu karşılamalı) DML ifadesinin ne olduğunun önemli olmadığı varsayımını yapar. Dolayısıyla Roman Pekar'ın çözümü kadar eksiksiz olmasa da, daha verimlidir.

Bu yaklaşımla, tablo başına bir "INSERT, UPDATE, DELETE" tetikleyicisi olan, bize A) eylem sırası üzerinde tam kontrol ve b) çok eylemli uygulanabilir eylem başına bir kod uygulaması yapma olanağına sahibiz. (Açıkçası, her uygulama modelinin avantajları ve dezavantajları vardır; sistemlerinizi gerçekten en iyi sonuç için bireysel olarak değerlendirmeniz gerekir.)

Disk erişimi olmadığından "mevcut (« eklenen / silinen »'den * seçin" ifadelerinin çok etkili olduğunu unutmayın ( 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

Bağlamımda olan bu çözüm için teşekkürler. Güncellenmiş / eklenen satırın LastUpdated sütununu güncellemenin bir yolunu önerir misiniz? Ayrıca, silinen satırın kimliğini başka bir tabloya kaydetmenin bir yolunu önerir misiniz (anahtar oluşturulabilir)?
Sébastien

0

Hızlı çözüm MySQL

Bu arada: MySQL PDO kullanıyorum.

(1) Bir otomatik artış tablosunda, her komut dosyası ilk kez çalıştırıldığında artan sütundan en yüksek değeri (sütun adım = id) almanız yeterlidir:

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

(2) MySQL sorgusunu normalde yaptığınız gibi çalıştırın ve sonucu tamsayıya dönüştürün, örneğin:

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

(3) "DUPLICATE ANAHTAR GÜNCELLEMESİNE GİRİN ..." sorgusundan sonra, son eklenen kimliği istediğiniz şekilde alın, örn:

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

(4) Karşılaştırma ve tepki verme: lastInsertId, tablodaki en yüksek değerden yüksekse, büyük olasılıkla bir INSERT, değil mi? Ve tam tersi.

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

Hızlı ve belki kirli olduğunu biliyorum. Ve bu eski bir yazı. Ama, hey, uzun zamandır bir çözüm arıyordum ve belki birisi yine de yolumu biraz faydalı buluyor. Herşey gönlünce olsun!


0

sadece basit bir yol

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 

SSMS IDE'ye göre sözdiziminiz, IF BEGIN - END ELSE BEGIN - END bloklarında mantığınızı nasıl sarmaladığınızla doğru değil.
Erutan409

0

İlk senaryoda, tablonuzda KİMLİK sütunu olduğunu varsaydım

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

İkinci senaryoda IDENTITTY sütununu kullanmanıza gerek yok

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

Bazılarımın bana yardım edebileceği aynı sorunum var. Aşağıdaki bağlantıya bakın stackoverflow.com/questions/26043106/…
Ramesh S

0
DECLARE @INSERTEDCOUNT INT,
        @DELETEDCOUNT INT

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

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

EĞER güncelleme

 @INSERTEDCOUNT = 1
 @DELETEDCOUNT = 1

yerleştirilmesi durumunda

 @INSERTEDCOUNT = 1
 @DELETEDCOUNT = 0

0

Bu exists (select * from inserted/deleted)sorguları uzun zamandır kullandım, ancak yine de boş CRUD işlemleri için yeterli değil (kayıtlarda insertedve deletedtablolarda kayıt olmadığında ). Bu konuyu biraz araştırdıktan sonra daha kesin bir çözüm buldum:

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) > 0Sütunun güncellenip güncellenmediğini görmek de mümkündür , ancak çok sayıda sütuna sahip tablolar için güvenli değildir. Hesaplamanın biraz karmaşık bir yolunu kullandım (aşağıdaki yararlı makaleye bakın).

Ayrıca, bu yaklaşım yine de bazı güncellemeleri yanlış olarak ekler olarak sınıflandırır (tablodaki her sütun güncellemeden etkileniyorsa) ve muhtemelen yalnızca varsayılan değerlerin eklendiği ekleri siler, ancak bunlar nadir işlemlerin kralı olarak sınıflandırır ( benim sistemimde kiralama). Bunun yanı sıra, şu anda bu çözümü nasıl geliştireceğimizi bilmiyorum.


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

bunu yaparım:

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

1 -> ekle

2 -> sil

3 -> güncelleme

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;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.