삽입 업데이트 트리거 삽입 또는 업데이트 여부를 결정하는 방법


162

하나의 열 (Desc)이 테이블 A의 열 (예 : Col1)에 삽입 / 업데이트 된 값과 같은 값을 갖는 테이블 B의 모든 행을 삭제하는 테이블 A에 삽입, 업데이트 트리거를 작성해야합니다. 업데이트 및 삽입 사례를 모두 처리 할 수 ​​있도록 작성하는 방법은 무엇입니까? 업데이트 또는 삽입에 대해 트리거가 실행되는지 어떻게 확인합니까?

답변:


167

트리거는 특별해야 INSERTED하고 DELETED데이터 "다음"과 "이전"추적 테이블을. 따라서 IF EXISTS (SELECT * FROM DELETED)업데이트를 탐지하는 것과 같은 것을 사용할 수 있습니다 . DELETED업데이트시 행만 있지만 항상 행이 있습니다.INSERTED 있습니다.

CREATE TRIGGER 에서 "inserted"를 찾으십시오 .

편집, 2011 년 11 월 23 일

주석 후이 답변은 오직 트리거 INSERTEDUPDATED트리거에 대한 것입니다.
분명히, INSERTED위에서 언급 한 것처럼 DELETE 트리거는 "항상 행"을 가질 수 없습니다.


전체 답변은 아래 @MikeTeeVee의 답변을 참조하십시오. 이것은 불완전합니다.
Lorenz Meyer

1
@LorenzMeyer 원래 질문은 필요하지 않습니다. 또한 존재합니다 (SELECT * FROM DELETED). 왜 그것이 완전하지 않다고 생각하는지 모르겠다.
gbn

무엇 @LorenzMeyer도 언급 될 수있다 성명은 " 당신은 업데이 트에서 삭제 된 행을 가지고 있지만, 거기에 항상 행 삽입에. "이것은 아니다 항상 업데이트 / 삽입 트리거가 호출 삽입이있을 때 시간이 있기 때문에 사실 빈. 내 대답에서 나는 데이터가 변경되는 것을 제거하는 술어에 의해 이것이 어떻게 발생할 수 있는지 설명합니다. 이 경우에도 DML 시도에 대해 트리거가 여전히 호출되지만 DELETED 및 INSERTED 테이블은 비어 있습니다. SQL은 여전히 ​​각 DML 시도를 기록하려는 시간 (데이터를 변경하지 않더라도)을 고려하기 때문입니다.
MikeTeeVee

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

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

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

    ...

    END

1
SELECT 1 FROM INSERTED도 쓰려고합니다. 의도를보다 명확하게
알리는 것으로 생각되지만

26
IF EXISTS (SELECT * ...)와 IF EXISTS (SELECT 1) ...은 정확히 동일한 성능을 갖습니다. 행을 읽거나 가져 오지 않습니다. 실제로 IF EXISTS (SELECT 1/0 ...)를 사용할 수도 있으며 여전히 작동하며 0으로 나누기 오류가 발생하지 않습니다.
Endrju

1
나는 삽입, 업데이트 및 삭제를 위해 별도의 트리거를 작성했습니다. 이제는 결합 될 수 있다는 것을 알게되었습니다!
UJS

2
누군가가 두 개의 다른 행을 INSERT 및 DELETE에 쿼리를 작성하면 (새 행 삽입 및 동일한 스크립트에서 다른 행 삭제) 위의 방식으로 설정된 트리거는 실제로 의도를하더라도 UPDATE로 식별 할 수 있습니까? INSERTED / DELETED sql-tables에 데이터가 있기 때문에 실제로 업데이트가 아닙니까?
mche

87

아무것도 삭제하지 않는 delete 문을 실행하면 이러한 제안 중 많은 부분이 고려되지 않습니다.
ID가 테이블에 존재하지 않는 값과 같은 곳을 삭제하려고한다고 가정 해보십시오.
트리거는 여전히 호출되지만 삭제 또는 삽입 된 테이블에는 아무 것도 없습니다.

이것을 안전하게 사용하십시오 :

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

그들의 답변에 대한 @KenDog와 @Net_Prog에게 감사드립니다.
나는 그들의 대본에서 이것을 만들었다.


3
존재하지 않는 삭제를 처리하는 상입니다. 잘 했어!
Andrew Wolfe

6
행에 영향을 미치지 않는 UPDATE가 있거나 INSERT에도 영향을 줄 수 있습니다.
Razvan Socol

@AndrewWolfe? 무슨 말씀 이세요? 이 질문은 구체적으로 "테이블 A에 삽입, 업데이트 트리거를 작성해야 합니다 "라고 명시되어 있습니다. DELETE 트리거에 대해서는 아무것도 없습니다.
ypercubeᵀᴹ

@ ypercubeᵀᴹ 죄송합니다. 트리거의 약 80 %가 세 가지 타이밍을 모두 포함합니다.
Andrew Wolfe

18

나는 다음을 사용하고 있으며 아무것도 삭제하지 않는 delete 문을 올바르게 감지합니다.

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
그러나 이것은 아무것도 삽입하지 않거나 아무것도 업데이트하지 않는 명령문을 잘못 감지합니다.
Roman Pekar

11

많은 검색을 한 후 INSERT, UPDATE 및 DELETE 트리거 동작의 세 가지 조건을 모두 처리하는 단일 SQL Server 트리거의 정확한 예를 찾을 수 없었습니다. 마지막으로 DELETE 또는 UPDATE가 발생할 때 공통 DELETED 테이블에이 두 작업에 대한 레코드가 포함된다는 사실에 대해 설명하는 텍스트 줄을 찾았습니다. 그런 정보를 바탕으로 트리거가 활성화 된 이유를 결정하는 작은 동작 루틴을 만들었습니다. 이 유형의 인터페이스는 공통 구성과 INSERT vs. UPDATE 트리거에서 발생하는 특정 조치가있을 때 가끔 필요합니다. 이 경우 UPDATE 및 INSERT에 대해 별도의 트리거를 작성하면 유지 보수 문제가됩니다. (즉, 필요한 공통 데이터 알고리즘 수정을 위해 두 트리거가 올바르게 업데이트 되었습니까?)

이를 위해 Microsoft SQL Server에 대한 하나의 트리거에서 INSERT, UPDATE, DELETE를 처리하기 위해 다음과 같은 다중 트리거 이벤트 코드 스 니펫을 제공하고 싶습니다.

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

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

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

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

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

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

9

나는 중첩 된 ifs가 약간 혼란스럽고 믿습니다.

평지가 중첩 된 것보다 낫다 [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

이 시도..

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

4

@Alex가 게시 한 답변도 좋아하지만 위의 @Graham 솔루션 에이 변형을 제공합니다.

이것은 첫 번째 테스트에 COLUMNS_UPDATED를 사용하는 것과는 반대로 INSERTED 및 UPDATED 테이블에 레코드 존재를 독점적으로 사용합니다. 또한 최종 사례가 고려되었다는 것을 알고 편집증 프로그래머 구호를 제공합니다 ...

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

다음과 같은 문장으로 NOOP를 얻습니다.

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

첫 번째 END가 잘못 들여 쓰기 된 것 같습니다 ! (첫 번째 BEGIN가 어디에서 문을 닫았
는가?

else if와 final else는 단일 문장을 포함합니다. IF / Else가 단일 진술이므로 시작과 끝은 실제로 불필요합니다. 들여 쓰기를 수정했습니다. 도와 주셔서 감사합니다.
greg

3

이것은 더 빠른 방법 일 수 있습니다.

DECLARE @action char(1)

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

4
columns_updated ()가 큰 varbinary를 리턴하므로 많은 수의 열이있는 테이블에서는이 방법이 작동하지 않습니다. 따라서 0의 기본값은 columns_updated ()에서 반환 된 값보다 훨씬 작은 내부 저장 번호로 설정되므로 "> 0"이 실패합니다.
Graham

3

제공되는 두 가지 솔루션의 잠재적 인 문제점은 작성 방법에 따라 업데이트 쿼리가 레코드 0을 업데이트하고 삽입 쿼리가 레코드 0을 삽입 할 수 있다는 것입니다. 이 경우 삽입 및 삭제 레코드 세트가 비어 있습니다. 삽입 및 삭제 레코드 세트가 모두 비어있는 경우에는 아무 것도하지 않고 트리거를 종료하려고 할 수도 있습니다.


2

Grahams에서 멋진 해결책이 아니라면 작은 오류를 발견했습니다.

IF COLUMNS_UPDATED () < > 0-
최상위 비트가 SIGNED 정수 부호 비트 ... (?)로 해석되므로> 0 대신 삽입 또는 업데이트 해야합니다. 전체적으로 :

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

1

이것은 나를 위해 속임수를합니다 :

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

한 번에 모든 열을 업데이트 할 수있는 것은 아니므로 특정 열이 다음과 같이 업데이트되는지 확인할 수 있습니다.

IF UPDATE([column_name])

이 솔루션의 과제는 열 이름을 알아야한다는 것입니다. 다른 것 중 일부는 스 니펫 라이브러리에서 붙여 넣기 만 복사 할 수 있도록 설계되었습니다. 작은 점이지만 모든 것을 고려하면 일반적인 솔루션은 사례 별 솔루션보다 낫습니다. 이모.
greg mar

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

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

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

        --do stuff here
    End

1
성능상의 이유로 COUNT (*)를 사용하지 않습니다. 전체 테이블을 스캔해야합니다. 대신 DELETED와 동일한 IF EXISTS (SELECT * FROM INSERTED)를 사용하여 플래그를 설정합니다. 나는 보통 몇 행만 영향을 받는다는 것을 알고 있지만 왜 시스템 속도가 느려집니다.
Endrju

솔루션과 매우 비슷한 것을 게시하려고했습니다. 조금 장황하지만 읽을 수 있습니다. 공정한 거래. 나는 또한 위의 Grahms 솔루션을 좋아합니다.
greg mar

1

나는 "컴퓨터 과학 우아한"솔루션을 좋아합니다. 내 솔루션은 여기에서 각각 [inserted] 및 [deleted] 의사 테이블을 한 번 눌러 상태를 가져오고 결과를 비트 매핑 변수에 넣습니다. 그런 다음 INSERT, UPDATE 및 DELETE의 각 가능한 조합을 트리거 전체에서 효율적인 이진 평가 (쉽게 INSERT 또는 DELETE 조합 제외)로 쉽게 테스트 할 수 있습니다.

행이 수정되지 않은 경우 (대부분의 경우를 충족해야 함) DML 문의 내용이 중요하지 않다고 가정합니다. 따라서 Roman Pekar의 솔루션만큼 완벽하지는 않지만 더 효율적입니다.

이 접근 방식을 사용하면 테이블 당 하나의 "FOR INSERT, UPDATE, DELETE"트리거가 가능하므로 A) 동작 순서를 완벽하게 제어하고 b) 다중 동작 적용 가능한 동작마다 하나의 코드 구현을 제공 할 수 있습니다. (모든 구현 모델에는 장단점이 있으므로 시스템을 실제로 가장 잘 작동하는지 개별적으로 평가해야합니다.)

디스크에 액세스 할 수 없기 때문에 "존재 (select * from«inserted / deleted»)"문은 매우 효율적입니다 ( https://social.msdn.microsoft.com/Forums/en-US/01744422-23fe-42f6 -9ab0-a255cdf2904a ).

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

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

set nocount on;

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

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

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

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

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

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

drop table dbo.TrigAction
;
GO

내 맥락에 맞는이 솔루션에 감사드립니다. 업데이트 / 삽입 된 행의 LastUpdated 열을 업데이트하는 방법을 추천 하시겠습니까? 삭제 된 행의 ID를 다른 테이블에 저장하는 방법을 권장합니까 (키 구성 가능)?
Sébastien

0

빠른 솔루션 MySQL

그건 그렇고 : 나는 MySQL PDO를 사용하고 있습니다.

(1) 자동 증가 테이블에서 모든 스크립트가 처음 실행될 때마다 증가 된 열에서 가장 높은 값 (내 열 이름 = id)을 가져옵니다.

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

(2) 정상적으로 MySQL 쿼리를 실행하고 결과를 정수로 캐스트하십시오.

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

(3) "INSERT INTO ... ON DUPLICATE KEY UPDATE"쿼리는 마지막으로 삽입 된 ID를 원하는 방식으로 가져옵니다. 예 :

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

(4) 비교 및 ​​반응 : lastInsertId가 테이블에서 가장 높은 값보다 높으면 아마도 INSERT 일 것입니다. 그 반대.

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

나는 그것이 빠르고 더럽다는 것을 안다. 그리고 그것은 오래된 게시물입니다. 그러나, 나는 오랫동안 해결책을 찾고 있었고 누군가 어쨌든 내 방식이 다소 유용하다는 것을 알 수 있습니다. 모두 제일 좋다!


0

간단한 방법

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

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

END 

내 SSMS IDE에 따르면 구문이 IF BEGIN-END ELSE BEGIN-END 블록에서 논리를 래핑하는 방법에 맞지 않습니다.
Erutan409

0

첫 번째 시나리오에서는 테이블에 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

두 번째 시나리오에서는 IDENTITTY 열을 사용할 필요가 없습니다.

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

어떤 사람이 나를 도울 수있는 동일한 문제가 있습니다. 다음 링크를 참조하십시오 stackoverflow.com/questions/26043106/…
Ramesh S

0
DECLARE @INSERTEDCOUNT INT,
        @DELETEDCOUNT INT

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

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

업데이트하는 경우

 @INSERTEDCOUNT = 1
 @DELETEDCOUNT = 1

삽입하면

 @INSERTEDCOUNT = 1
 @DELETEDCOUNT = 0

0

exists (select * from inserted/deleted)쿼리를 오랫동안 사용 했지만 빈 CRUD 작업에는 충분하지 않습니다 (레코드 inserteddeleted테이블 이없는 경우 ). 따라서이 주제를 조금 연구 한 후에 더 정확한 해결책을 찾았습니다.

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

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

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

columns_updated() & power(2, column_id - 1) > 0열이 업데이트되었는지 확인할 수도 있지만 열 수가 많은 테이블에는 안전하지 않습니다. 나는 약간 복잡한 계산 방법을 사용했습니다 (아래 유용한 기사 참조).

또한이 방법은 일부 업데이트를 삽입으로 잘못 분류하지만 (테이블의 모든 열이 업데이트의 영향을받는 경우) 아마도 기본값 만 삭제로 삽입되는 삽입을 분류하지만 드문 작업의 왕입니다 ( 내 시스템에 임대되어 있습니다). 그 외에도 현재이 솔루션을 개선하는 방법을 모르겠습니다.


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

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

0

나는 이것을한다:

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

1-> 삽입

2-> 삭제

3-> 업데이트

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

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


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

0
DECLARE @ActionType CHAR(6);
SELECT  @ActionType = COALESCE(CASE WHEN EXISTS(SELECT * FROM INSERTED)
                                     AND EXISTS(SELECT * FROM DELETED)  THEN 'UPDATE' END,
                               CASE WHEN EXISTS(SELECT * FROM DELETED)  THEN 'DELETE' END,
                               CASE WHEN EXISTS(SELECT * FROM INSERTED) THEN 'INSERT' END);
PRINT   @ActionType;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.