COLUMNS UPDATED: примеры (SQL)
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. Динамическое создание журнала изменений только для обновленных столбцов.
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. Обработка обновления любого столбца в группе.
-- Проверка, обновлен ли хотя бы один из столбцов: Col2, Col3, Col5.
IF (COLUMNS_UPDATED() & 38) > 0 -- 38 = 2 + 4 + 32 (биты 1,2,4)
BEGIN
PRINT 'Обновлен хотя бы один из контрольных столбцов.';
ENDПример 3. Комбинация с функцией UPDATE() для комплексной проверки.
-- Если обновлен столбец А, но не обновлен столбец 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') и затем проверять отдельные столбцы.