2017-04-05 7 views
3

처음으로 게시물을 작성하십시오 ...SQL Server : 업데이트 트랜잭션이 트리거에서 발생했는지 여부를 지정하는 옵션?

테이블이 업데이트되거나 행이 삽입 될 때 하나의 열을 업데이트해야하므로 트리거 (AFTER INSERT, UPDATE)가 생성되었습니다. 문제는 삽입에 업데이트 문이 포함되어 트리거가 다시 실행된다는 사실 때문에 재귀 적이라는 것입니다.

또한 두 개의 서로 다른 트리거로 INSERTUPDATE을 분리하려고했지만, 대신에 다른 트리거가 있기 때문에 나는 때문에 상자 응용 프로그램 기본값 중에, sp_settriggerorder()trigger_nestlevel()와 함께 문제로 실행했습니다.

내 질문은 업데이트가 응용 프로그램 자체 또는 내 트리거에서 온 여부는 IF 절 진술을 사용할 수있는 방법이있다? 케이스, 그것이 내 방아쇠 인 경우, 내가 돌아가는 경우에 쉽게 ELSE 할 수 있고, 더 이상 재귀 적이 될 수 없습니다.

CREATE TRIGGER [dbo].[JobCardMetlInsertUpdateItemDesc] 
ON [dbo].[JobCardMetl] AFTER INSERT 
AS 
    BEGIN TRANSACTION [Description] 

    UPDATE JobCardMetl 
    SET JobCardMetl.Description = item.Description 
    FROM JobCardMetl 
    INNER JOIN item ON JobCardMetl.Item = item.item 
    WHERE JobCardMetl.RecordDate = (SELECT MAX(JobCardMetl.RecordDate) 
            FROM JobCardMetl) 

    COMMIT TRANSACTION [Description] 
+0

트리거 재귀 (트리거 직접 트리거 자체)는 데이터베이스 또는 서버 (?) 수준에서 비활성화 될 수 있습니다. 물론 그것은 모든 것에 영향을 미친다. – RBarryYoung

답변

3

귀하의 트리거는 매우 의심스러운 : 그것은 INSERTED pseudotable을 참조하지 않습니다. 이것은 트리거가 INSERT에 영향을받지 않는 레코드를 업데이트한다는 것을 의미합니다. 항상 큰 코드 - 냄새입니다.

재귀 트리거의 문제에 대한 일반적인 해결책은 열이 즉, 업데이트되고 있는지에주의하는 것입니다. UPDATED() 등을 사용하여 어떤 행과 자연의 비즈니스 로직은 재귀를 중지해야합니다 (예. 가드 검사가 필요하지 않기 때문에, 업데이트 할 아무것도 발견하지해야 중첩 트리거). SET CONTEXT_INFOCONTEXT_INFO() :

궁극적으로 당신은 논리적 망치를 사용할 수 있습니다. 당신이 그것을 확인하고, 그것을 설정하고 트리거에서 청소하십시오. 이미 설정된 경우 트리거에서 중첩 된 것입니다. 청소 부분이 중요합니다. 또한 세션마다 단 하나의 컨텍스트 정보 만 있기 때문에 다른 응용 프로그램/dev도 동일한 작업을 수행하지 않습니다 (SQL 2016에서는이 점을 개선했습니다).

0

당신이 설명은 당신이로 업데이트 할 것과 여전히 다른 여부를 확인할 수 있습니다. 동일한 경우 업데이트하지 않습니다. 그렇게하면 끝없는 재귀를 피할 수 있습니다.

또한 WHERE 조건을 사용하면 업데이트를 현재 삽입 된 레코드로 제한하고 싶지만 삽입 된 레코드가있는 가상 INSERTED 테이블을 사용할 수 있습니다.

마지막으로, 원자 문 새 트랜잭션을 시작하는 과잉 보인다. 트리거는 어쨌든 INSERT 트리거 문이 실행되는 트랜잭션 내에서 실행됩니다.

그래서 다음과 같이 트리거를 만들 수있는, 함께 모든 것을 가지고 (나는 RecordDate 가정 고유 레코드를 식별 - 기본 키 무엇이든으로 변경) :

CREATE TRIGGER [dbo].[JobCardMetlInsertUpdateItemDesc] 
ON [dbo].[JobCardMetl] AFTER INSERT 
AS 
    UPDATE JobCardMetl 
    SET j.Description = item.Description 
    FROM JobCardMetl j 
    INNER JOIN item ON j.Item = item.item 
    INNER JOIN INSERTED i ON i.RecordDate = j.RecordDate 
    WHERE j.Description IS NULL OR j.Description <> item.Description