COLUMNS UPDATED: примеры (SQL)

Применение COLUMNS_UPDATED для отслеживания изменений столбцов
Раздел: Функции работы с триггерами
COLUMNS_UPDATED: varbinary

Описание функции COLUMNS_UPDATED

Функция COLUMNS_UPDATED применяется в Transact-SQL для определения обновленных столбцов внутри триггера AFTER UPDATE или INSTEAD OF UPDATE. Функция не имеет аргументов и возвращает битовую маску типа varbinary. Каждый бит в маске соответствует определенному столбцу таблицы, на которую создан триггер. Бит, установленный в значение 1 (или ON), указывает, что соответствующий столбец был изменен оператором UPDATE.

Биты нумеруются слева направо, начиная с 0. Первый (самый левый) байт представляет столбцы с номерами от 0 до 7, второй байт - столбцы от 8 до 15 и т.д. Для проверки, был ли обновлен конкретный столбец, используется побитовый оператор & (AND) и целочисленное значение, где позиция бита соответствует номеру столбца (2n, где n - номер столбца).

Функция возвращает значение только в контексте выполнения триггера. Вне триггера ее вызов не имеет смысла и может привести к ошибке или неопределенному поведению.

Примеры использования

Пример 1. Проверка обновления одного столбца.

CREATE TRIGGER trg_CheckUpdate 
ON Employees
AFTER UPDATE
AS
BEGIN
    IF (COLUMNS_UPDATED() & 4) > 0 -- Проверка третьего столбца (бит 2)
    BEGIN
        PRINT 'Столбец Salary был обновлен.';
    END
END;
-- При выполнении UPDATE, затрагивающем столбец Salary, будет выведено сообщение.

Пример 2. Проверка обновления нескольких столбцов.

CREATE TRIGGER trg_CheckMultiple 
ON Products
AFTER UPDATE
AS
BEGIN
    IF (COLUMNS_UPDATED() & 6) = 6 -- Проверка обновления второго и третьего столбцов (биты 1 и 2)
    BEGIN
        PRINT 'Столбцы Price и Quantity обновлены одновременно.';
    END
END;

Пример 3. Использование для таблицы с большим количеством столбцов.

-- Проверка обновления 10-го столбца (бит 9).
IF (SUBSTRING(COLUMNS_UPDATED(), 2, 1) & 2) > 0 
BEGIN
    PRINT 'Десятый столбец обновлен.';
END

Похожие функции в MS SQL

Функция UPDATE() проверяет, был ли обновлен указанный столбец. Она принимает имя столбца в качестве аргумента и возвращает логическое значение. Эта функция проще в использовании для проверки одного столбца, но менее эффективна при массовой проверке нескольких столбцов.

IF UPDATE(Salary) -- Проверка обновления столбца Salary
BEGIN
    PRINT 'Столбец Salary изменен.';
END

Функция TRIGGER_NESTLEVEL() возвращает уровень вложенности триггеров, что может быть полезно в сложных сценариях каскадных обновлений.

Распространенные ошибки

Ошибка 1. Использование функции вне контекста триггера UPDATE.

SELECT COLUMNS_UPDATED(); -- Вне триггера
-- Результат: NULL или неопределенное поведение.

Ошибка 2. Неправильный расчет битовой маски для столбцов с номером более 7.

-- Для проверки 10-го столбца (индекс 9) неверно:
IF (COLUMNS_UPDATED() & 512) > 0 -- 512 это 2^9, но бит находится во втором байте.
-- Верный способ через SUBSTRING.

Ошибка 3. Забывают, что нумерация столбцов начинается с 0. Проверка первого столбца требует значения 1 (20), второго - 2 (21).

Изменения в последних версиях

В последних версиях Microsoft SQL Server (включая SQL Server 2019 и 2022) функция COLUMNS_UPDATED не претерпела значительных изменений в синтаксисе или поведении. Однако, всегда рекомендуется обращаться к официальной документации для конкретной версии, так как могут быть изменения в работе с оптимизированными для памяти таблицами или в составе других функций.

Расширенные примеры

Пример 1. Динамическое создание журнала изменений только для обновленных столбцов.

Пример sql
CREATE TRIGGER trg_AuditUpdate 
ON Orders
AFTER UPDATE
AS
BEGIN
    DECLARE @UpdatedColumns varchar(max) = '';
    -- Проверка каждого столбца таблицы (предположим, 5 столбцов)
    IF (COLUMNS_UPDATED() & 1) > 0 SET @UpdatedColumns = @UpdatedColumns + 'OrderDate, ';
    IF (COLUMNS_UPDATED() & 2) > 0 SET @UpdatedColumns = @UpdatedColumns + 'CustomerID, ';
    IF (COLUMNS_UPDATED() & 4) > 0 SET @UpdatedColumns = @UpdatedColumns + 'Amount, ';
    IF (COLUMNS_UPDATED() & 8) > 0 SET @UpdatedColumns = @UpdatedColumns + 'Status, ';
    IF (COLUMNS_UPDATED() & 16) > 0 SET @UpdatedColumns = @UpdatedColumns + 'Notes, ';
    
    IF LEN(@UpdatedColumns) > 0
    BEGIN
        SET @UpdatedColumns = LEFT(@UpdatedColumns, LEN(@UpdatedColumns) - 1);
        INSERT INTO AuditLog (TableName, UpdatedColumns, ChangeDate)
        VALUES ('Orders', @UpdatedColumns, GETDATE());
    END
END;

Пример 2. Обработка обновления любого столбца в группе.

Пример sql
-- Проверка, обновлен ли хотя бы один из столбцов: Col2, Col3, Col5.
IF (COLUMNS_UPDATED() & 38) > 0 -- 38 = 2 + 4 + 32 (биты 1,2,4)
BEGIN
    PRINT 'Обновлен хотя бы один из контрольных столбцов.';
END

Пример 3. Комбинация с функцией UPDATE() для комплексной проверки.

Пример sql
-- Если обновлен столбец А, но не обновлен столбец B.
IF UPDATE(A) AND (COLUMNS_UPDATED() & 2) = 0 
BEGIN
    PRINT 'Столбец A обновлен, а столбец B нет.';
END

Аналоги в других СУБД

MySQL: Проверка обновления столбцов осуществляется через сравнение значений NEW и OLD в триггере. Прямого аналога функции COLUMNS_UPDATED нет.

CREATE TRIGGER before_update 
BEFORE UPDATE ON employees
FOR EACH ROW
BEGIN
    IF NEW.salary <> OLD.salary THEN
        -- Действие при изменении salary
    END IF;
END;

Oracle: В триггерах можно использовать предикаты UPDATING('column_name') для проверки обновления конкретного столбца.

IF UPDATING('SALARY') THEN
    DBMS_OUTPUT.PUT_LINE('Salary updated');
END IF;

PostgreSQL: Как и в MySQL, используется сравнение NEW и OLD. Также можно использовать конструкцию IF (tg_op = 'UPDATE') и затем проверять отдельные столбцы.

MS SQL COLUMNS_UPDATED function comments

En
COLUMNS UPDATED Returns a varbinary bit pattern indicating which columns in a table were inserted or updated