복붙노트

[SQL] 트리거가 테이블에있을 때 OUTPUT 절을 사용하여 UPDATE를 사용할 수 없습니다

SQL

트리거가 테이블에있을 때 OUTPUT 절을 사용하여 UPDATE를 사용할 수 없습니다

나는 OUTPUT 쿼리가있는 UPDATE를 수행하고 있습니다 :

UPDATE BatchReports
SET IsProcessed = 1
OUTPUT inserted.BatchFileXml, inserted.ResponseFileXml, deleted.ProcessedDate
WHERE BatchReports.BatchReportGUID = @someGuid

이 문장은 잘 괜찮습니다; 트리거는 테이블에 정의 될 때까지. 그럼 내 UPDATE 문은 오류 334을 얻을 것이다 :

이제이 문제는 SQL Server 팀에 의해 블로그 포스트에 설명되어 있습니다 :

그리고 그들은 또한 솔루션을 제공 :

내가 블로그 게시물의 전체의 머리 또는 꼬리를 만들 수 없습니다 제외.

그래서 내 질문을 물어 보자 : 어떻게 내가 그렇게 작동하는지 내 UPDATE를 변경해야합니까?

해결법

  1. ==============================

    1.이 제한을 해결하려면 당신은 출력 INTO 필요 ... 뭔가를. 예를 들면 대상은 그 중에서 선택할 수 중간 나타난 변수를 선언.

    이 제한을 해결하려면 당신은 출력 INTO 필요 ... 뭔가를. 예를 들면 대상은 그 중에서 선택할 수 중간 나타난 변수를 선언.

    DECLARE @T TABLE (
      BatchFileXml    XML,
      ResponseFileXml XML,
      ProcessedDate   DATE,
      RowVersion      BINARY(8) )
    
    UPDATE BatchReports
    SET    IsProcessed = 1
    OUTPUT inserted.BatchFileXml,
           inserted.ResponseFileXml,
           deleted.ProcessedDate,
           inserted.Timestamp
    INTO @T
    WHERE  BatchReports.BatchReportGUID = @someGuid
    
    SELECT *
    FROM   @T 
    

    이 열을 영향을 트리거하면 OUTPUT - 보내고 유용한 결과를 찾을 수 없습니다 다음 것을 같은 방법으로 UPDATE 문 자체에 의해 수정 된 행을 다시 쓰는 경우로서 다른 대답에주의하지만이의 하위 집합입니다 트리거. 상기 기술은 트리거 감사 목적으로 다른 테이블에 기록하거나 원래 행 트리거에 다시 쓰여진 경우라도 삽입 된 ID 값을 반환 같은 다른 경우에 잘 작동한다.

  2. ==============================

    2.가시성 경고 : 음주 가장 높은 투표 대답을 사용할 수 없습니다. 그것은 잘못된 값을 제공 할 것입니다. 그것이 잘못 방법에 대해 읽어보십시오.

    가시성 경고 : 음주 가장 높은 투표 대답을 사용할 수 없습니다. 그것은 잘못된 값을 제공 할 것입니다. 그것이 잘못 방법에 대해 읽어보십시오.

    SQL Server 2008 R2의 출력 작업에 UPDATE를 만드는 데 필요한 kludge을 감안할 때, 난 내 쿼리를 변경 :

    UPDATE BatchReports  
    SET IsProcessed = 1
    OUTPUT inserted.BatchFileXml, inserted.ResponseFileXml, deleted.ProcessedDate
    WHERE BatchReports.BatchReportGUID = @someGuid
    

    에:

    SELECT BatchFileXml, ResponseFileXml, ProcessedDate FROM BatchReports
    WHERE BatchReports.BatchReportGUID = @someGuid
    
    UPDATE BatchReports
    SET IsProcessed = 1
    WHERE BatchReports.BatchReportGUID = @someGuid
    

    기본적으로 내가 OUTPUT 사용을 중단. 엔티티 프레임 워크 자체가 바로이 같은 해킹을 사용하기 때문에이 그렇게 나쁘지 않다!

    희망 2014 2016 2018 2012 더 나은 구현을해야합니다.

    우리가 검색 할 OUTPUT 절을 사용하려고했다와 함께 시작된이 문제를 테이블에있는 값 "후"

    UPDATE BatchReports
    SET IsProcessed = 1
    OUTPUT inserted.LastModifiedDate, inserted.RowVersion, inserted.BatchReportID
    WHERE BatchReports.BatchReportGUID = @someGuid
    

    그것은 다음 SQL Server에서 잘 알고 제한 (이뤄져 - 수정 버그) 조회수 :

    우리는 우리가 OUTPUT 결과를 잡아 중간 테이블 변수를 사용하는 것을 시도 그래서 :

    DECLARE @t TABLE (
       LastModifiedDate datetime,
       RowVersion timestamp, 
       BatchReportID int
    )
    
    UPDATE BatchReports
    SET IsProcessed = 1
    OUTPUT inserted.LastModifiedDate, inserted.RowVersion, inserted.BatchReportID
    INTO @t
    WHERE BatchReports.BatchReportGUID = @someGuid
    
    SELECT * FROM @t
    

    당신이 테이블 (심지어 임시 테이블 변수)에 타임 스탬프를 삽입 할 수 없습니다 있기 때문에 그 실패를 제외하고.

    우리는 비밀리에 타임 스탬프가 실제로 64 비트 (일명 8 바이트) 부호없는 정수는 것을 알고있다. 우리는 오히려 타임 스탬프보다 이진 (8)을 사용하는 우리의 임시 테이블 정의를 변경할 수 있습니다 :

    DECLARE @t TABLE (
       LastModifiedDate datetime,
       RowVersion binary(8), 
       BatchReportID int
    )
    
    UPDATE BatchReports
    SET IsProcessed = 1
    OUTPUT inserted.LastModifiedDate, inserted.RowVersion, inserted.BatchReportID
    INTO @t
    WHERE BatchReports.BatchReportGUID = @someGuid
    
    SELECT * FROM @t
    

    그리고 값 것을 제외하고는 작품은 잘못이다.

    업데이트가 완료된 후에 존재로 타임 스탬프 RowVersion의 우리의 복귀는 타임 스탬프의 값이 아닙니다 :

    우리 테이블에 출력되는 값이 아닌 값들이 UPDATE 문의 끝에 있었다 같다 때문이다 :

    이 수단 :

    동일 행 내의 임의의 값을 수정 트리거 임의의 사실이다. 출력 업데이트 월말하지 않습니다 OUTPUT 값.

    이 고통스러운 현실은 BOL에 설명되어 있습니다 :

    닷넷 엔티티 프레임 워크는 낙관적 동시성에 대한 rowversion를 사용합니다. EF의는 업데이트를 실행 후와 타임 스탬프의 값을 알고에 따라 달라집니다.

    당신은 중요한 데이터의 출력을 사용할 수 없기 때문에, 마이크로 소프트의 엔티티 프레임 워크는 내가하는 것과 같은 해결 방법을 사용합니다 :

    애프터 값을 검색하기 위해, 엔티티 프레임 워크 문제 :

    UPDATE [dbo].[BatchReports]
    SET [IsProcessed] = @0
    WHERE (([BatchReportGUID] = @1) AND ([RowVersion] = @2))
    
    SELECT [RowVersion], [LastModifiedDate]
    FROM [dbo].[BatchReports]
    WHERE @@ROWCOUNT > 0 AND [BatchReportGUID] = @1
    

    출력을 사용하지 마십시오.

    네, 그것은 경쟁 조건을 앓고 있지만 최고의 SQL 서버가 할 수 있습니다.

    엔티티 프레임 워크가 무엇을 수행합니다

    SET NOCOUNT ON;
    
    DECLARE @generated_keys table([CustomerID] int)
    
    INSERT Customers (FirstName, LastName)
    OUTPUT inserted.[CustomerID] INTO @generated_keys
    VALUES ('Steve', 'Brown')
    
    SELECT t.[CustomerID], t.[CustomerGuid], t.[RowVersion], t.[CreatedDate]
    FROM @generated_keys AS g
       INNER JOIN Customers AS t
       ON g.[CustomerGUID] = t.[CustomerGUID]
    WHERE @@ROWCOUNT > 0
    
  3. ==============================

    3.왜 테이블 변수에 필요한 모든 열을 넣어? 우리는 기본 키를 필요로하고 우리는 UPDATE 후 모든 데이터를 읽을 수 있습니다. 당신이 트랜잭션을 사용에는 경기가 없습니다 :

    왜 테이블 변수에 필요한 모든 열을 넣어? 우리는 기본 키를 필요로하고 우리는 UPDATE 후 모든 데이터를 읽을 수 있습니다. 당신이 트랜잭션을 사용에는 경기가 없습니다 :

    DECLARE @t TABLE (ID INT PRIMARY KEY);
    
    BEGIN TRAN;
    
    UPDATE BatchReports SET 
        IsProcessed = 1
    OUTPUT inserted.ID INTO @t(ID)
    WHERE BatchReports.BatchReportGUID = @someGuid;
    
    SELECT b.* 
    FROM @t t JOIN BatchReports b ON t.ID = b.ID;
    
    COMMIT;
    
  4. from https://stackoverflow.com/questions/13198476/cannot-use-update-with-output-clause-when-a-trigger-is-on-the-table by cc-by-sa and MIT license