Поделиться через


Реализация инструкции UPDATE с предложением FROM или вложенными запросами

Область применения: SQL Server База данных SQL Azure Управляемый экземпляр SQL Azure

В инструкции Transact-SQL UPDATE в скомпилированном в собственном коде модуле T-SQL следующие элементы синтаксиса не поддерживаются:

  • Предложение FROM
  • Подзапросы

Напротив, предыдущих элементов поддерживаются в модулях, скомпилированных в исходном коде, в инструкции SELECT.

Инструкции UPDATE с предложением FROM часто используются для обновления данных в таблице, основанной на возвращающем табличное значение параметре (TVP), или для обновления столбцов в таблице в триггере AFTER.

Сценарий обновления на основе TVP см. в разделе Реализация функциональности MERGE в скомпилированной в собственном коде хранимой процедуре.

В следующем примере показано обновление, выполненное в триггере. В таблице для столбца с именем LastUpdated будет установлено текущее значение даты и времени после обновления. Обходной путь выполняет отдельные обновления, используя следующие элементы:

  • Табличную переменную со столбцом IDENTITY.
  • Цикл WHILE для итерации строк в табличной переменной.

Далее приведена исходная инструкция T-SQL UPDATE.

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

В образце кода T-SQL в следующем блоке показан обходной путь, который обеспечивает хорошую производительность. Решение реализуется в скомпилированном в собственном коде триггере. В коде крайне необходимо обратить внимание на следующие моменты:

  • Тип с именем dbo.Type1, который является типом оптимизированной для памяти таблицы.
  • Цикл WHILE в триггере.
    • Цикл получает строки из Inserted друг за другом.
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

Вот результирующий набор.

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