programing

테이블에 트리거가 있는 경우 OUTPUT 절과 함께 UPDATE를 사용할 수 없습니다.

muds 2023. 4. 21. 21:33
반응형

테이블에 트리거가 있는 경우 OUTPUT 절과 함께 UPDATE를 사용할 수 없습니다.

는 지금 금연inging를 하고 있습니다.UPDATEOUTPUT 삭제:

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

테이블에 트리거가 정의될 때까지 이 문장은 정상입니다. 나의 ★★★★★★★★★★★★★★★★★.UPDATE스테이트먼트에 에러 334가 표시됩니다.

DML 문의 대상 테이블 'BatchReports'에 INTO 절이 없는 OUTPUT 절이 포함된 경우 트리거를 활성화할 수 없습니다.

이 문제는 SQL Server 팀의 블로그 투고에서 설명하고 있습니다.UPDATE with OUTPUT 절 – Triggers – and SQLMoreResults :

에러 메세지는 자동적으로 설명된다.

또한 다음과 같은 솔루션을 제공합니다.

응용 프로그램이 INTO 절을 사용하도록 변경되었습니다.

블로그 게시물 전체를 이해할 수 없다는 것만 빼면요.

질문 하나 할게요. ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★UPDATE동하도 록할 ????

「 」를 참조해 주세요.

가시성 경고:다른 대답은 하지 마세요.잘못된 값을 제공합니다.왜 그것이 잘못된 것인지 계속 읽어보세요.


UPDATEOUTPUTSQL Server 2008 R2는 SQL Server 2008 R2를 사용합니다.

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엔티티 프레임워크 자체에서 동일한 해킹을 사용하는 만큼 나쁘지 않습니다.

바라건대. 2012년 2014년 2016년 2018년 2019년 2020년은 더 나은 구현이 될 것입니다.


업데이트: OUTPUT 사용은 유해합니다.

는 '우리끼리'를요.OUTPUT테이블 내의 "after" 값을 취득하는 절:

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

그러면 SQL Server의 기존 제한("수정되지 않음")에 도달합니다.

DML 문의 대상 테이블 'BatchReports'에 INTO 절이 없는 OUTPUT 절이 포함된 경우 트리거를 활성화할 수 없습니다.

회피책 #1

할 수 있는 합니다.TABLE the " " " 。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

,, 이, 이, 이, 이, 이, 이, 이, except, except, except, except, except, except, except, except, except, except, except, except, except, except, except, except, except,timestamp테이블(일시 테이블 변수도 포함)로 이동합니다.

회피책 #2

는 몰래 있다timestamp는 실제로는 64비트(8바이트) 부호 없는 정수입니다. 테이블 수 .binary(8)timestamp:

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업데이트하다

  • 반환된 타임스탬프:0x0000000001B71692
  • 실제 타임스탬프:0x0000000001B71693

는 값 「」이 있기 입니다.OUTPUTUPDATE 스테이트먼트의 마지막과 같은 값은 에 기재되어 있지 않습니다.

  • UPDATE 문작 。
    • 행 변경
      • 타임스탬프가 업데이트됩니다(예: 2 3).
    • OUTPUT이 새 타임스탬프(예: 3)를 검색합니다.
    • 트리거 실행
      • 행을 다시 변경하다
        • 타임스탬프가 업데이트됩니다(예: 3 → 4).
  • UPDATE 문이 완료되었습니다.
  • OUTPUT은 3반환합니다(잘못된).

이것은 다음을 의미합니다.

  • 타임스탬프는 UPDATE 스테이트먼트(4)의 끝에 존재하기 때문에 취득되지 않습니다.
  • 대신 타임스탬프가 UPDATE 스테이트먼트(3)의 중간에서 취득됩니다.
  • 올바른 타임스탬프를 얻을 수 없습니다.

행의 값을 변경하는 트리거도 마찬가지입니다.OUTPUT업데이트 종료 시점에서는 값이 출력되지 않습니다.

즉, OUTPUT이 올바른 값을 반환하는 것을 신뢰할 수 없습니다.

이 고통스러운 현실은 BOL에 기록되어 있습니다.

OUTPUT에서 반환되는 열은 INSERT, UPDATE 또는 DELETE 문이 완료된 후 트리거가 실행되기 전의 데이터를 그대로 반영합니다.

엔티티 프레임워크는 이를 어떻게 해결했습니까?

동시성을 행 합니다.NET 엔티티 프레임워크(Optimistic Concurrency) 행 버전(Rowversion).는 EF IT의 .timestamp현재 상태를 유지합니다.

「 」는 할 수 에,OUTPUTMicrosoft 엔티티 프레임워크

회피책 #3 - 최종 - OUTPUT 절 사용 안 함

다음 을 취득하기 위해 엔티티 프레임워크에서는 다음 문제가 발생합니다.

UPDATE [dbo].[BatchReports]
SET [IsProcessed] = @0
WHERE (([BatchReportGUID] = @1) AND ([RowVersion] = @2))

SELECT [RowVersion], [LastModifiedDate]
FROM [dbo].[BatchReports]
WHERE @@ROWCOUNT > 0 AND [BatchReportGUID] = @1

마세요OUTPUT.

네, 경합 상황에 시달리지만 이것이 SQL Server가 할 수 있는 최선의 방법입니다.

INSERT는?

Entity Framework에서 수행하는 작업:

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

'아니다', '아니다', '아니다', '아니다', '아니다', '아니다'를 씁니다.SELECTOUTPUT 을 output output output output output output output output 。

하려면 , 「」가 합니다.OUTPUT INTO ... 중간 한 후 "타깃으로 선언합니다."SELECT것으으그

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 

가 에 와 같이UPDATE당신이 있는 열에 영향을 줄 수 있는 방식으로 진술 그 자체OUTPUT-ing 그러면 결과가 유용하지 않을 수 있지만 이는 트리거의 하위 집합에 불과합니다.감사 목적을 위해 다른 테이블에 기록을 트리거하거나 트리거에 원래 행이 다시 입력된 경우에도 삽입된 ID 값을 반환하는 등 다른 경우에는 위의 기술이 정상적으로 작동합니다.

필요한 열을 모두 표 변수에 넣는 이유는 무엇입니까?기본 키만 있으면 업데이트 후 모든 데이터를 읽을 수 있습니다.트랜잭션을 사용할 때는 경주가 없습니다.

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;

트리거는 코드의 다른 부분을 조용히 암살할 수 있는 코드 냄새입니다.대신 저장 프로시저를 사용하십시오.출력이 하지 않습니다.따라서 Interside Of 트리거가 발생하면 INT를 사용해도 출력이 작동하지 않으며 Scope_Identity도 작동하지 않습니다.
예를 들어 다음과 같습니다.

CREATE   Trigger [DI].[TRG_AJC_BeforeInsert]
On [DI].[AJC]
INSTEAD OF INSERT
As
Set NoCount on
Insert Into [DI].[AJC] (val1, date2)
From Select [val1], getDate()

출력 또는 ScopeIdentity 결과는 반환되지 않습니다.스코프 ID가 아직 생성되지 않았기 때문에 결과가 없고 OUTPUT을 읽을 때 생성되지 않았기 때문에 Output에 대한 결과가 없습니다.

네 유일한 희망은 방아쇠가 다른 테이블에 삽입하지 않는 거야그런 다음 @@identity를 사용할 수 있습니다.그러나 세션 중에 다른 테이블이 업데이트/삽입된 경우 @@Identity는 원하는 ScopedIdentity가 아닌 다른 테이블의 ID를 반환합니다.

언급URL : https://stackoverflow.com/questions/13198476/cannot-use-update-with-output-clause-when-a-trigger-is-on-the-table

반응형