Sisipkan Pembaruan memicu cara menentukan apakah memasukkan atau memperbarui


162

Saya perlu menulis Sisipan, Perbarui Pemicu pada tabel A yang akan menghapus semua baris dari tabel B yang satu kolomnya (katakanlah Desc) memiliki nilai seperti nilai yang dimasukkan / diperbarui di kolom tabel A (misalkan Col1). Bagaimana saya berkeliling menulis sehingga saya bisa menangani Pembaruan dan Masukkan kasus. Bagaimana saya menentukan apakah pelatuk dijalankan untuk pembaruan atau masukkan.

Jawaban:


167

Pemicu memiliki tabel khusus INSERTEDdan DELETEDuntuk melacak data "sebelum" dan "setelah". Jadi, Anda dapat menggunakan sesuatu seperti IF EXISTS (SELECT * FROM DELETED)untuk mendeteksi pembaruan. Anda hanya memiliki baris pada DELETEDsaat pembaruan, tetapi selalu ada baris diINSERTED .

Cari "dimasukkan" di CREATE TRIGGER .

Edit, 23 Nov 2011

Setelah berkomentar, jawaban ini hanya untuk INSERTEDdan UPDATEDmemicu.
Jelas, pemicu DELETE tidak dapat memiliki "selalu baris INSERTED" seperti yang saya katakan di atas


Lihatlah jawaban @ MikeTeeVee di bawah untuk jawaban yang lengkap. Yang ini tidak lengkap.
Lorenz Meyer

1
@LorenzMeyer pertanyaan asli tidak memerlukan itu. Saya juga memiliki EXIS (SELECT * FROM DELETED). Tidak yakin mengapa Anda berpikir itu tidak lengkap ...
gbn

Yang dimaksud oleh @LorenzMeyer adalah pernyataan " Anda hanya memiliki baris dalam DELETED pada pembaruan, tetapi selalu ada baris dalam INSERTED. " Ini tidak selalu benar karena ada kalanya Pembaruan / Masukkan Pemicu Dipanggil dan INSERT adalah kosong. Dalam jawaban saya, saya menjelaskan bagaimana ini bisa disebabkan oleh Predikat yang menghilangkan data apa pun dari perubahan. Dalam acara ini, Pemicu masih dipanggil untuk upaya DML, tetapi tabel DELETED dan INSERTED kosong. Ini karena SQL masih menyumbang waktu ketika Anda ingin mencatat setiap upaya DML (bahkan ketika mereka tidak mengubah data apa pun).
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
Saya suka menulis SELECT 1 FROM INSERTED juga karena saya pikir itu menandakan niat lebih jelas, tapi saya akan kecewa dengan programmer MSSQL jika ini membuat perbedaan dalam konteks ini ...
Lukáš Lánský

26
JIKA ADA (SELECT * ...) dan JIKA ADA (SELECT 1) ... memiliki kinerja yang persis sama. Baris tidak dibaca atau tidak diambil sama sekali. Bahkan Anda juga dapat menggunakan JIKA ADA (SELECT 1/0 ...) dan itu masih akan berfungsi dan tidak akan menyebabkan bagi dengan nol kesalahan.
Endrju

1
Saya sedang membuat Pemicu terpisah untuk disisipkan, diperbarui, dan dihapus. Sekarang bagus untuk mengetahui bahwa mereka dapat digabungkan!
UJS

2
Jika seseorang menulis kueri ke INSERT dan DELETE dua baris yang berbeda (masukkan baris baru dan hapus baris lain dalam skrip yang sama), mungkinkah pemicu yang diatur dengan cara di atas akan benar-benar mengidentifikasi itu sebagai PEMBARUAN (meskipun maksudnya adalah sebenarnya bukan pembaruan) karena ada data dalam sql-tables TERMASUK?
mche

87

Banyak dari saran ini tidak memperhitungkan jika Anda menjalankan pernyataan hapus yang tidak menghapus apa pun.
Katakanlah Anda mencoba menghapus di mana ID sama dengan beberapa nilai yang tidak ada dalam tabel.
Pemicu Anda masih dipanggil tetapi tidak ada dalam tabel Dihapus atau Dimasukkan.

Gunakan ini agar aman:

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

Terima kasih khusus kepada @KenDog dan @Net_Prog atas jawaban mereka.
Saya membangun ini dari skrip mereka.


3
Yang ini hadiah, penanganan yang tidak ada dihapus. Kerja bagus!
Andrew Wolfe

6
Kami mungkin juga memiliki UPDATE yang tidak memengaruhi baris (atau bahkan INSERT).
Razvan Socol

@AndrewWolfe? Apa yang kamu katakan? Pertanyaannya secara spesifik menyatakan bahwa "Saya perlu menulis Sisipan, Perbarui Pemicu pada tabel A" . Tidak ada tentang DELETE yang memicu.
ypercubeᵀᴹ

@ ypercubeᵀᴹ maaf, sekitar 80% dari pemicu saya mencakup ketiga timing.
Andrew Wolfe

18

Saya menggunakan yang berikut ini, juga mendeteksi dengan benar pernyataan yang tidak menghapus apa pun:

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
yang ini salah mendeteksi pernyataan yang memasukkan apa pun atau tidak memperbarui apa pun.
Roman Pekar

11

Setelah banyak pencarian saya tidak dapat menemukan contoh yang tepat dari pemicu SQL Server tunggal yang menangani semua (3) tiga kondisi tindakan pemicu INSERT, UPDATE, dan DELETE. Saya akhirnya menemukan satu baris teks yang berbicara tentang fakta bahwa ketika DELETE atau UPDATE terjadi, tabel DELETED umum akan berisi catatan untuk dua tindakan ini. Berdasarkan informasi itu, saya kemudian membuat tindakan rutin kecil yang menentukan mengapa pemicu telah diaktifkan. Jenis antarmuka ini kadang-kadang diperlukan ketika ada konfigurasi umum dan tindakan khusus untuk terjadi pada pemicu INSERT vs UPDATE. Dalam kasus ini, membuat pemicu terpisah untuk UPDATE dan INSERT akan menjadi masalah pemeliharaan. (Yaitu kedua pemicu diperbarui dengan benar untuk memperbaiki algoritma data umum yang diperlukan?)

Untuk itu, saya ingin memberikan potongan kode peristiwa multi-pemicu berikut untuk menangani INSERT, UPDATE, DELETE dalam satu pemicu untuk 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

Saya percaya bersarang sedikit membingungkan dan:

Flat lebih baik daripada bersarang [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

Coba ini..

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

sementara saya juga menyukai jawaban yang diposting oleh @Alex, saya menawarkan variasi ini untuk solusi @ Graham di atas

ini secara eksklusif menggunakan catatan keberadaan dalam tabel INSERTED dan UPDATED, yang bertentangan dengan menggunakan COLUMNS_UPDATED untuk pengujian pertama. Ini juga memberikan bantuan programmer paranoid mengetahui bahwa kasus terakhir telah dipertimbangkan ...

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

Anda akan mendapatkan NOOP dengan pernyataan seperti berikut:

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

Tampaknya ENDindentasi yang pertama salah! (menyebabkan mempertanyakan di mana yang pertama BEGINditutup)
S.Serpooshan

yang lain jika dan yang lain berisi pernyataan tunggal. awal dan akhir benar-benar tidak perlu karena IF / Else adalah satu pernyataan. Saya memperbaiki indentasi. Terima kasih untuk bantuannya.
greg

3

Ini mungkin cara yang lebih cepat:

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
Cara ini tidak berfungsi untuk tabel dengan sejumlah besar kolom karena column_updated () mengembalikan varbinary yang sangat besar. Jadi "> 0" gagal karena 0 default ke nomor yang disimpan secara internal jauh lebih kecil dari nilai yang dikembalikan dari column_updated ()
Graham

3

Masalah potensial dengan dua solusi yang ditawarkan adalah, tergantung pada bagaimana mereka ditulis, permintaan pembaruan dapat memperbarui nol catatan dan permintaan memasukkan dapat memasukkan nol catatan. Dalam kasus ini, rekaman yang Dimasukkan dan Dihapus akan kosong. Dalam banyak kasus, jika kedua recordset yang Dimasukkan dan Dihapus kosong Anda mungkin hanya ingin keluar dari pelatuk tanpa melakukan apa pun.


2

Saya menemukan kesalahan kecil dalam Grahams jika tidak solusi keren:

Seharusnya JIKA COLUMNS_UPDATED () < > 0 - masukkan atau perbarui
daripada> 0 mungkin karena bit teratas ditafsirkan sebagai bit tanda integer SIGNED ... (?). Jadi totalnya:

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

Ini berguna bagi saya:

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

Karena tidak semua kolom dapat diperbarui pada satu waktu, Anda dapat memeriksa apakah kolom tertentu sedang diperbarui oleh sesuatu seperti ini:

IF UPDATE([column_name])

Tantangan dengan solusi ini adalah Anda harus tahu nama kolom. Beberapa yang lain dirancang sedemikian rupa sehingga Anda bisa menyalinnya dari pustaka potongan. Poin kecil, tetapi semua hal dipertimbangkan, solusi generik lebih baik daripada solusi spesifik kasus. MENURUT OPINI SAYA.
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
Saya tidak akan menggunakan COUNT (*) untuk alasan kinerja - perlu memindai seluruh tabel. Saya malah akan menetapkan bendera dengan menggunakan JIKA ADA (SELECT * FROM INSERTED), sama untuk DELETED. Saya tahu biasanya hanya ada beberapa baris yang terpengaruh, tetapi mengapa memperlambat sistem.
Endrju

Saya hendak memposting sesuatu yang sangat mirip sebagai solusi. Agak bertele-tele, tapi sangat mudah dibaca. Tradeoff yang adil. Saya juga Suka Solusi Grahms di atas.
greg

1

Saya suka solusi yang "ilmu komputer elegan." Solusi saya di sini mengenai pseudotables [yang dimasukkan] dan [dihapus] masing-masing sekali untuk mendapatkan statusnya dan menempatkan hasilnya dalam variabel yang sedikit dipetakan. Kemudian setiap kemungkinan kombinasi INSERT, UPDATE dan DELETE dapat dengan mudah diuji di seluruh pemicu dengan evaluasi biner yang efisien (kecuali untuk kombinasi INSERT atau DELETE yang tidak mungkin).

Itu membuat asumsi bahwa tidak masalah apa pernyataan DML jika tidak ada baris yang dimodifikasi (yang harus memenuhi sebagian besar kasus). Jadi sementara itu tidak selengkap solusi Roman Pekar, itu lebih efisien.

Dengan pendekatan ini, kami memiliki kemungkinan satu pemicu "UNTUK INSERT, UPDATE, DELETE" per tabel, memberi kami A) kontrol penuh atas urutan tindakan dan b) satu implementasi kode per tindakan yang dapat diterapkan multi tindakan. (Jelas, setiap model implementasi memiliki pro dan kontra; Anda perlu mengevaluasi sistem Anda secara individual untuk apa yang benar-benar bekerja paling baik.)

Perhatikan bahwa pernyataan "ada (pilih * dari« disisipkan / dihapus »)" sangat efisien karena tidak ada akses disk ( 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

Terima kasih atas solusi yang sesuai dengan konteks saya. Apakah Anda merekomendasikan cara untuk memperbarui kolom LastUpdated dari baris yang diperbarui / dimasukkan? Apakah Anda juga merekomendasikan cara untuk menyimpan ID dari baris yang dihapus pada tabel lain (dapat terdiri dari kunci)?
Sébastien

0

Solusi cepat MySQL

Omong-omong: Saya menggunakan MySQL PDO.

(1) Dalam tabel kenaikan otomatis, dapatkan nilai tertinggi (nama kolom saya = id) dari kolom yang bertambah setelah setiap skrip dijalankan terlebih dahulu:

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

(2) Jalankan permintaan MySQL seperti biasa, dan masukkan hasilnya ke integer, misalnya:

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

(3) Setelah kueri "INSERT INTO ... ON DUPLICATE KEY UPDATE", dapatkan id yang disisipkan terakhir dengan cara yang Anda sukai, misalnya:

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

(4) Bandingkan dan bereaksi: Jika InsertId terakhir lebih tinggi dari yang tertinggi dalam tabel, itu mungkin INSERT, kan? Dan sebaliknya.

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

Saya tahu ini cepat dan mungkin kotor. Dan itu adalah pos lama. Tapi, hei, saya sudah mencari solusi untuk waktu yang lama, dan mungkin seseorang menemukan cara saya agak berguna. Semua yang terbaik!


0

hanya cara sederhana

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 

Menurut IDE SSMS saya, sintaks Anda tidak benar dengan cara Anda membungkus logika Anda di IF BEGIN - END ELSE BEGIN - END blok.
Erutan409

0

Dalam skenario pertama saya menduga bahwa tabel Anda memiliki kolom IDENTITAS

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

Dalam skenario kedua tidak perlu menggunakan kolom 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

Saya memiliki masalah yang sama dengan seseorang yang dapat membantu saya. Lihat tautan berikut stackoverflow.com/questions/26043106/…
Ramesh S

0
DECLARE @INSERTEDCOUNT INT,
        @DELETEDCOUNT INT

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

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

JIKA pembaruannya

 @INSERTEDCOUNT = 1
 @DELETEDCOUNT = 1

jika penyisipannya

 @INSERTEDCOUNT = 1
 @DELETEDCOUNT = 0

0

Saya telah menggunakan exists (select * from inserted/deleted)pertanyaan itu untuk waktu yang lama, tapi itu masih tidak cukup untuk operasi CRUD kosong (ketika tidak ada catatan di dalam inserteddan deletedtabel). Jadi setelah meneliti topik ini sedikit saya menemukan solusi yang lebih tepat:

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'

Mungkin juga digunakan columns_updated() & power(2, column_id - 1) > 0untuk melihat apakah kolom diperbarui, tetapi tidak aman untuk tabel dengan jumlah kolom yang besar. Saya telah menggunakan cara penghitungan yang agak rumit (lihat artikel bermanfaat di bawah).

Juga, pendekatan ini masih akan salah mengklasifikasikan beberapa pembaruan sebagai sisipan (jika setiap kolom dalam tabel dipengaruhi oleh pembaruan), dan mungkin itu akan mengklasifikasikan sisipan di mana hanya nilai-nilai default yang dimasukkan sebagai dihapus, tetapi mereka adalah raja operasi yang jarang (pada sewa di sistem saya mereka). Selain itu, saya tidak tahu bagaimana meningkatkan solusi ini saat ini.


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

saya melakukan ini:

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

1 -> masukkan

2 -> hapus

3 -> pembaruan

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;
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.