FROM 또는 하위 쿼리를 사용하여 UPDATE 구현Implementing UPDATE with FROM or Subqueries

이 항목은 다음에 적용됩니다. 예SQL Server 예Azure SQL Database아니요Azure SQL Data Warehouse 아니요병렬 데이터 웨어하우스THIS TOPIC APPLIES TO: yesSQL ServeryesAzure SQL DatabasenoAzure SQL Data Warehouse noParallel Data Warehouse

고유하게 컴파일된 T-SQL 모듈은 FROM 절을 지원하지 않으며 UPDATE 문에서 하위 쿼리를 지원하지 않습니다(SELECT에서 지원됨).Natively compiled T-SQL modules do not support the FROM clause and do not support subqueries in UPDATE statements (they are supported in SELECT). FROM 절이 있는 UPDATE 문은 일반적으로 TVP(테이블 반환 매개 변수)에 따라 테이블의 정보를 업데이트하거나 AFTER 트리거에서 테이블의 열을 업데이트하는 데 사용됩니다.UPDATE statements with FROM clause are typically used to update information in a table based on a table-valued parameter (TVP), or to update columns in a table in an AFTER trigger.

TVP에 따라 업데이트하는 시나리오의 경우 고유하게 컴파일된 저장 프로시저에서 MERGE 기능 구현을 참조하세요.For the scenario of update based on a TVP, see Implementing MERGE Functionality in a Natively Compiled Stored Procedure.

아래 샘플에서는 트리거에서 수행되는 업데이트를 보여 줍니다. 테이블의 LastUpdated 열이 현재 날짜/시간 AFTER 업데이트로 업데이트됩니다.The below sample illustrates an update performed in a trigger - the LastUpdated column of the table is updated to the current date/time AFTER updates. 해결 방법은 ID 열과 함께 테이블 변수를 사용하고 WHILE 루프를 통해 테이블 변수에서 행을 반복하여 개별 업데이트를 수행하는 것입니다.The workaround uses a table variable with an identity column, and a WHILE loop to iterate of the rows in the table variable and perform individual updates.

원래 T-SQL UPDATE 문은 다음과 같습니다.Here is the original T-SQL UPDATE statement :

 UPDATE dbo.Table1  
     SET LastUpdated = SysDateTime()  
     FROM  
         dbo.Table1 t  
         JOIN Inserted i ON t.Id = i.Id;  

이 섹션의 샘플 T-SQL 코드는 좋은 성능을 제공하는 해결 방법을 보여 줍니다.The sample T-SQL code in this section demonstrates a workaround that provides good performance. 해결 방법은 고유하게 컴파일된 트리거에서 구현되었습니다.The workaround is implemented in a natively compiled trigger. 코드에서 주의해야 할 사항은 다음과 같습니다.Crucial to notice in the code are:

  • 메모리 최적화 테이블 형식인 dbo.Type1 형식The type named dbo.Type1, which is a memory-optimized table type.
  • 트리거의 WHILE 루프.The WHILE loop in the trigger.
    • 루프는 Inserted에서 행을 한 번에 하나씩 검색합니다.The loop retrieves the rows from Inserted one at a time.
   DROP TABLE IF EXISTS dbo.Table1;  
   go  
   DROP TYPE IF EXISTS dbo.Type1;  
   go  
   -----------------------------  
   -- Table and table type
   -----------------------------

   CREATE TABLE dbo.Table1  
   (  
       Id           INT        NOT NULL  PRIMARY KEY NONCLUSTERED,  
       Column2      INT        NOT NULL,  
       LastUpdated  DATETIME2  NOT NULL  DEFAULT (SYSDATETIME())  
   )  
       WITH (MEMORY_OPTIMIZED = ON);  
   go  


   CREATE TYPE dbo.Type1 AS TABLE  
   (  
       Id       INT NOT  NULL,  

       RowID    INT NOT  NULL  IDENTITY,  
       INDEX ix_RowID HASH (RowID) WITH (BUCKET_COUNT=1024)
   )   
       WITH (MEMORY_OPTIMIZED = ON);  
   go  
   ----------------------------- 
   -- trigger that contains the workaround for UPDATE with FROM 
   -----------------------------  

   CREATE TRIGGER dbo.tr_a_u_Table1  
       ON dbo.Table1  
       WITH NATIVE_COMPILATION, SCHEMABINDING  
       AFTER UPDATE  
   AS 
   BEGIN ATOMIC WITH  
       (  
       TRANSACTION ISOLATION LEVEL = SNAPSHOT,  
       LANGUAGE = N'us_english'  
       )  

     DECLARE @tabvar1 dbo.Type1;  

     INSERT @tabvar1 (Id)   
         SELECT Id FROM Inserted;  

     DECLARE  
         @i INT = 1,  @Id INT,  
         @max INT = SCOPE_IDENTITY();  

     ---- Loop as a workaround to simulate a cursor.
     ---- Iterate over the rows in the memory-optimized table  
     ----   variable and perform an update for each row.  

     WHILE @i <= @max  
     BEGIN  
         SELECT @Id = Id  
             FROM @tabvar1  
             WHERE RowID = @i;  

         UPDATE dbo.Table1  
             SET LastUpdated = SysDateTime()  
             WHERE Id = @Id;  

         SET @i += 1;  
     END  
   END  
   go  
   -----------------------------  
   -- Test to verify functionality
   -----------------------------  

   SET NOCOUNT ON;  

   INSERT dbo.Table1 (Id, Column2)  
       VALUES (1,9), (2,9), (3,600);  

   SELECT N'BEFORE-Update' AS [BEFORE-Update], *  
       FROM dbo.Table1  
       ORDER BY Id;  

   WAITFOR DELAY '00:00:01';  

   UPDATE dbo.Table1  
       SET   Column2 += 1  
       WHERE Column2 <= 99;  

   SELECT N'AFTER--Update' AS [AFTER--Update], *  
       FROM dbo.Table1  
       ORDER BY Id;  
   go  
   -----------------------------  

   /**** Actual output:  

   BEFORE-Update   Id   Column2   LastUpdated  
   BEFORE-Update   1       9      2016-04-20 21:18:42.8394659  
   BEFORE-Update   2       9      2016-04-20 21:18:42.8394659  
   BEFORE-Update   3     600      2016-04-20 21:18:42.8394659  

   AFTER--Update   Id   Column2   LastUpdated  
   AFTER--Update   1      10      2016-04-20 21:18:43.8529692  
   AFTER--Update   2      10      2016-04-20 21:18:43.8529692  
   AFTER--Update   3     600      2016-04-20 21:18:42.8394659  
   ****/