Chèn Cập nhật kích hoạt làm thế nào để xác định nếu chèn hoặc cập nhật


162

Tôi cần phải viết một Trình chèn, Cập nhật Kích hoạt trên bảng A sẽ xóa tất cả các hàng khỏi bảng B có một cột (giả sử Desc) có các giá trị như giá trị được chèn / cập nhật trong cột của bảng A (giả sử là Col1). Làm thế nào tôi có thể đi xung quanh viết nó để tôi có thể xử lý cả trường hợp Cập nhật và Chèn. Làm thế nào tôi có thể xác định nếu kích hoạt được thực hiện cho một bản cập nhật hoặc chèn.

Câu trả lời:


167

Kích hoạt có đặc biệt INSERTEDDELETEDbảng để theo dõi dữ liệu "trước" và "sau". Vì vậy, bạn có thể sử dụng một cái gì đó như IF EXISTS (SELECT * FROM DELETED)để phát hiện một bản cập nhật. Bạn chỉ có hàng trong DELETEDbản cập nhật, nhưng luôn có hàng trong INSERTED.

Tìm "chèn" trong CREATE TRIGGER .

Chỉnh sửa, ngày 23 tháng 11 năm 2011

Sau khi bình luận, câu trả lời này chỉ dành cho INSERTEDUPDATEDkích hoạt.
Rõ ràng, các trình kích hoạt XÓA không thể có "luôn luôn hàng INSERTED" như tôi đã nói ở trên


Hãy xem câu trả lời của @ MikeTeeVee dưới đây để có câu trả lời đầy đủ. Điều này là không đầy đủ.
Lorenz Meyer

1
@LorenzMeyer câu hỏi ban đầu không cần điều đó. Tôi cũng có EXISTS (CHỌN * TỪ BỊ XÓA). Không chắc chắn tại sao bạn nghĩ rằng nó chưa hoàn thành ...
gbn

Điều mà @LorenzMeyer cũng có thể đề cập đến là câu " Bạn chỉ có các hàng trong XÓA khi cập nhật, nhưng luôn có các hàng trong CHERTN. " Điều này không phải lúc nào cũng đúng bởi vì đôi khi, Trình kích hoạt / Chèn được gọi trống. Trong câu trả lời của tôi, tôi giải thích làm thế nào điều này có thể được gây ra bởi Vị ngữ loại bỏ bất kỳ dữ liệu nào thay đổi. Trong trường hợp này, Trình kích hoạt vẫn được gọi cho nỗ lực DML, nhưng các bảng XÓA và XÁC NHẬN đều trống. Điều này là do SQL vẫn chiếm số lần khi bạn muốn ghi nhật ký từng lần thử DML (ngay cả khi chúng không thay đổi bất kỳ dữ liệu nào).
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
Tôi cũng muốn viết CHỌN 1 TỪ CHỨNG MINH vì tôi nghĩ nó báo hiệu ý định rõ ràng hơn, nhưng tôi sẽ bị các lập trình viên MSSQL không đồng ý nếu điều này tạo ra bất kỳ sự khác biệt nào trong bối cảnh này ...
Lukáš Lánský

26
NẾU EXISTS (CHỌN * ...) và NẾU EXIST (CHỌN 1) ... có cùng hiệu suất. Hàng không được đọc cũng không được tải về. Trong thực tế, bạn cũng có thể sử dụng IF EXISTS (CHỌN 1/0 ...) và nó vẫn hoạt động và sẽ không gây ra lỗi chia cho số không.
Endrju

1
Tôi đã tạo các Triggers riêng biệt để chèn, cập nhật và xóa. Bây giờ thật tuyệt khi biết chúng có thể được kết hợp!
UJS

2
Nếu ai đó viết một truy vấn vào CHERTN và XÓA hai hàng khác nhau (chèn hàng mới và xóa một hàng khác trong cùng một tập lệnh), có thể trình kích hoạt được thiết lập theo cách trên sẽ thực sự xác định đó là CẬP NHẬT (mặc dù ý định không thực sự là một bản cập nhật) do có dữ liệu trong các bảng sql đã được xác nhận / xóa?
mche

87

Nhiều trong số các đề xuất này không được tính đến nếu bạn chạy một câu lệnh xóa mà không xóa gì cả.
Giả sử bạn cố gắng xóa nơi ID bằng một số giá trị không tồn tại trong bảng.
Trình kích hoạt của bạn vẫn được gọi nhưng không có gì trong các bảng Đã xóa hoặc Đã chèn.

Sử dụng để được an toà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)

Đặc biệt cảm ơn @KenDog và @Net_Prog vì câu trả lời của họ.
Tôi đã xây dựng điều này từ kịch bản của họ.


3
Đây là giải thưởng, xử lý xóa không tồn tại. Làm tốt lắm!
Andrew Wolfe

6
Chúng tôi cũng có thể có một CẬP NHẬT mà không ảnh hưởng đến hàng nào (hoặc thậm chí là CHERTN).
Razvan Socol

@AndrewWolfe? Bạn đang nói gì vậy? Câu hỏi nêu cụ thể rằng "Tôi cần phải viết Chèn, Cập nhật Kích hoạt trên bảng A" . Không có gì về kích hoạt XÓA.
ypercubeᵀᴹ

@ ypercubeᵀᴹ xin lỗi, khoảng 80% kích hoạt của tôi bao gồm cả ba thời gian.
Andrew Wolfe

18

Tôi đang sử dụng như sau, nó cũng phát hiện chính xác các câu lệnh xóa không xóa gì:

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
điều này không chính xác phát hiện các câu lệnh không chèn gì hoặc cập nhật gì cả.
Roman Pekar

11

Sau rất nhiều lần tìm kiếm, tôi không thể tìm thấy một ví dụ chính xác về một trình kích hoạt SQL Server duy nhất xử lý tất cả (3) ba điều kiện của các hành động kích hoạt INSERT, UPDATE và DELETE. Cuối cùng tôi đã tìm thấy một dòng văn bản nói về thực tế rằng khi XÓA hoặc CẬP NHẬT xảy ra, bảng XÓA phổ biến sẽ chứa một bản ghi cho hai hành động này. Dựa trên thông tin đó, sau đó tôi đã tạo một thói quen Hành động nhỏ xác định lý do tại sao kích hoạt đã được kích hoạt. Loại giao diện này đôi khi cần thiết khi có cả cấu hình chung và hành động cụ thể xảy ra trên trình kích hoạt INSERT so với UPDATE. Trong những trường hợp này, để tạo một trình kích hoạt riêng cho CẬP NHẬT và INSERT sẽ trở thành vấn đề bảo trì. (tức là cả hai kích hoạt được cập nhật đúng cách để sửa thuật toán dữ liệu chung cần thiết?)

Cuối cùng, tôi muốn đưa ra đoạn mã sự kiện đa kích hoạt sau đây để xử lý INSERT, UPDATE, DELETE trong một kích hoạt cho 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

Tôi tin rằng ifs lồng nhau hơi khó hiểu và:

Flat tốt hơn lồng nhau [Zen của 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

Thử cái này..

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

Mặc dù tôi cũng thích câu trả lời được đăng bởi @Alex, tôi cung cấp biến thể này cho giải pháp của @ Graham ở trên

điều này độc quyền sử dụng sự tồn tại của bản ghi trong các bảng ĐƯỢC CHỨNG MINH và CẬP NHẬT, trái ngược với việc sử dụng COLUMNS_UPDATED cho thử nghiệm đầu tiên. Nó cũng cung cấp cứu trợ lập trình viên hoang tưởng khi biết rằng trường hợp cuối cùng đã được xem xét ...

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

bạn sẽ nhận được NOOP với một tuyên bố như sau:

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

Có vẻ như đầu tiên ENDlà thụt lề sai! (gây ra câu hỏi nơi đầu tiên BEGINđược đóng lại)
S.Serpooshan

cái khác nếu và cuối cùng chứa các câu lệnh đơn. bắt đầu và kết thúc thực sự không cần thiết vì IF / Else là một câu lệnh đơn. Tôi đã sửa lỗi thụt lề. Cảm ơn đã giúp đỡ.
greg

3

Đây có thể là một cách nhanh hơn:

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
Cách này không hoạt động đối với các bảng có số lượng cột lớn vì Cột_updated () trả về một biến số rất lớn. Vì vậy, "> 0" không thành công vì 0 mặc định cho số được lưu trữ nội bộ nhỏ hơn nhiều so với giá trị được trả về từ Cột_updated ()
Graham

3

Một vấn đề tiềm ẩn với hai giải pháp được đưa ra là, tùy thuộc vào cách chúng được viết, một truy vấn cập nhật có thể cập nhật các bản ghi bằng 0 và một truy vấn chèn có thể chèn các bản ghi bằng không. Trong những trường hợp này, các bản ghi được chèn và xóa sẽ trống. Trong nhiều trường hợp, nếu cả hai bản ghi được chèn và đã xóa đều trống, bạn có thể chỉ muốn thoát kích hoạt mà không làm gì cả.


2

Tôi đã tìm thấy một lỗi nhỏ trong giải pháp tuyệt vời của Grahams:

Nó phải là IF COLUMNS_UPDATED () < > 0 - chèn hoặc cập nhật
thay vì> 0 có thể vì bit trên cùng được hiểu là bit ký hiệu số nguyên đã ký ... (?). Vì vậy, trong tổng số:

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

Đây là mẹo cho tôi:

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

Vì không phải tất cả các cột có thể được cập nhật tại một thời điểm, bạn có thể kiểm tra xem một cột cụ thể có được cập nhật bởi một cái gì đó như thế này không:

IF UPDATE([column_name])

Một thách thức với giải pháp này là bạn phải biết một tên cột. Một số trong những cái khác được thiết kế sao cho bạn chỉ có thể sao chép dán từ thư viện đoạn trích. Điểm nhỏ, nhưng tất cả những điều được xem xét, một giải pháp chung là tốt hơn so với một giải pháp cụ thể trường hợp. IMHO.
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
Tôi sẽ không sử dụng COUNT (*) vì lý do hiệu suất - nó cần quét toàn bộ bảng. Thay vào đó, tôi sẽ đặt cờ bằng cách sử dụng IF EXISTS (CHỌN * TỪ CHỨNG MINH), tương tự cho XÓA. Tôi biết bình thường chỉ có vài hàng bị ảnh hưởng, nhưng tại sao hệ thống lại chậm.
Endrju

Tôi đã định đăng một cái gì đó rất giống như một giải pháp. Nó hơi dài dòng, nhưng rất dễ đọc. Trao đổi công bằng. Tôi cũng thích giải pháp Grahms ở trên.
greg

1

Tôi thích các giải pháp là "khoa học máy tính thanh lịch." Giải pháp của tôi ở đây đánh vào các giả danh [đã chèn] và [đã xóa] mỗi lần để lấy trạng thái của chúng và đặt kết quả vào một biến được ánh xạ bit. Sau đó, mỗi sự kết hợp có thể của INSERT, UPDATE và DELETE có thể dễ dàng được kiểm tra trong suốt quá trình kích hoạt với các đánh giá nhị phân hiệu quả (ngoại trừ kết hợp INSERT hoặc DELETE không có khả năng).

Nó đưa ra giả định rằng không có vấn đề gì với câu lệnh DML nếu không có hàng nào được sửa đổi (điều này sẽ đáp ứng phần lớn các trường hợp). Vì vậy, trong khi nó không hoàn chỉnh như giải pháp của Roman Pekar, thì nó hiệu quả hơn.

Với cách tiếp cận này, chúng tôi có khả năng một trình kích hoạt "CHO ​​XÁC NHẬN, CẬP NHẬT, XÓA" trên mỗi bảng, cho chúng tôi A) kiểm soát hoàn toàn trật tự hành động và b) thực hiện một mã cho mỗi hành động áp dụng nhiều hành động. (Rõ ràng, mọi mô hình triển khai đều có ưu và nhược điểm; bạn sẽ cần đánh giá riêng các hệ thống của mình để biết những gì thực sự hoạt động tốt nhất.)

Lưu ý rằng các câu lệnh "tồn tại (chọn * từ« được chèn / xóa ») rất hiệu quả do không có quyền truy cập đĩ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

Cảm ơn cho giải pháp này mà feets trong bối cảnh của tôi. Bạn có muốn giới thiệu một cách để cập nhật cột LastUpdated của hàng được cập nhật / chèn không? Bạn cũng có thể đề xuất một cách để lưu trữ trên một bảng khác ID của hàng đã xóa (có thể được tạo thành khóa) không?
Sébastien

0

Giải pháp nhanh chóng MySQL

Nhân tiện: Tôi đang sử dụng MySQL PDO.

(1) Trong bảng tăng tự động, chỉ cần lấy giá trị cao nhất (tên cột của tôi = id) từ cột tăng sau khi mỗi tập lệnh chạy trước:

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

(2) Chạy truy vấn MySQL như bạn bình thường và chuyển kết quả thành số nguyên, ví dụ:

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

(3) Sau khi truy vấn "XÁC NHẬN VÀO ... TRÊN CẬP NHẬT TỪ KHÓA", lấy id được chèn cuối cùng theo cách bạn muốn, ví dụ:

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

(4) So sánh và phản ứng: Nếu lastInsertId cao hơn mức cao nhất trong bảng, thì đó có lẽ là một CHERTN, phải không? Và ngược lại.

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

Tôi biết nó nhanh và có thể bẩn. Và đó là một bài viết cũ. Nhưng, này, tôi đã tìm kiếm một giải pháp trong một thời gian dài và có lẽ ai đó cũng thấy cách của tôi có phần hữu ích. Tất cả là tốt nhất!


0

chỉ cách đơn giản

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 

Theo IDE SSMS của tôi, cú pháp của bạn không chính xác với cách bạn gói logic của mình trong IF BEGIN - END ELSE BEGIN - END.
Erutan409 ngày

0

Trong kịch bản đầu tiên, tôi cho rằng bảng của bạn có cột 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

Trong kịch bản thứ hai, không cần sử dụng cột 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

Tôi có cùng một vấn đề một số có thể giúp tôi. Xem liên kết sau stackoverflow.com/questions/26043106/
Ấn

0
DECLARE @INSERTEDCOUNT INT,
        @DELETEDCOUNT INT

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

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

NẾU cập nhật của nó

 @INSERTEDCOUNT = 1
 @DELETEDCOUNT = 1

nếu nó chèn

 @INSERTEDCOUNT = 1
 @DELETEDCOUNT = 0

0

Tôi đã sử dụng các exists (select * from inserted/deleted)truy vấn đó trong một thời gian dài, nhưng nó vẫn không đủ cho các hoạt động CRUD trống (khi không có bản ghi inserteddeletedbảng). Vì vậy, sau khi nghiên cứu chủ đề này một chút, tôi đã tìm thấy giải pháp chính xác hơn:

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'

Cũng có thể sử dụng columns_updated() & power(2, column_id - 1) > 0để xem cột có được cập nhật hay không, nhưng nó không an toàn cho các bảng có số lượng cột lớn. Tôi đã sử dụng một cách tính toán hơi phức tạp (xem bài viết hữu ích bên dưới).

Ngoài ra, cách tiếp cận này vẫn sẽ phân loại không chính xác một số cập nhật dưới dạng chèn (nếu mọi cột trong bảng bị ảnh hưởng bởi cập nhật) và có thể nó sẽ phân loại các chèn trong đó chỉ có các giá trị mặc định được chèn dưới dạng xóa, nhưng đó là vua của các hoạt động hiếm (tại cho thuê trong hệ thống của tôi họ). Bên cạnh đó, tôi không biết làm thế nào để cải thiện giải pháp này vào lúc này.


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

tôi làm việc này:

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

1 -> chèn

2 -> xóa

3 -> cập nhật

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;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.