Partilhar via


Implementar UPDATE com FROM ou Subqueries

Aplica-se a:SQL ServerBanco de Dados SQL do AzureInstância Gerenciada SQL do Azure

Na instrução Transact-SQL UPDATE, num módulo T-SQL compilado nativamente, os seguintes elementos de sintaxe não são suportados:

  • A cláusula FROM
  • Subqueries

Em contraste, os elementos anteriores são suportados em módulos compilados nativamente na instrução SELECT.

As instruções UPDATE com uma cláusula FROM são frequentemente usadas para atualizar informação numa tabela com base num parâmetro de valor de tabela (TVP), ou para atualizar colunas numa tabela num gatilho AFTER.

Para o cenário de atualização baseada num TVP, veja Implementar a Funcionalidade MERGE num Procedimento Armazenado Compilado Nativamente.

O exemplo seguinte ilustra uma atualização realizada num trigger. Na tabela, a coluna chamada LastUpdated está definida para a data-hora atual APÓS as atualizações. A solução alternativa realiza atualizações individuais utilizando os seguintes itens:

  • Uma variável de tabela que tem uma coluna IDENTITY.
  • Um ciclo WHILE para iterar as linhas na variável da tabela.

Aqui está a declaração original da T-SQL UPDATE:

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

O código T-SQL de exemplo no bloco seguinte demonstra uma solução alternativa que oferece bom desempenho. A solução alternativa é implementada num trigger compilado nativamente. É crucial notar os seguintes elementos no código:

  • O tipo chamado dbo.Type1, que é um tipo de tabela otimizado para memória.
  • O loop WHILE no gatilho.
    • O ciclo recupera as linhas de "Inserted" uma a uma.
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

Aqui está o conjunto de resultados.

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