T-SQL: какие КОЛОННЫ изменились после обновления? - PullRequest
5 голосов
/ 26 января 2010

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

TABLE (id int ident, foo varchar(50), bar varchar(50))

Начальное значение:

id   foo   bar
-----------------
1    hi    there

Я тогда выполню UPDATE tbl SET foo = 'hi', bar = 'something else' WHERE id = 1

То, что я хочу знать, это то, что столбец изменил свое значение, и каково было его первоначальное значение, и каково его новое значение.

В приведенном выше примере я хотел бы видеть, что столбец "bar" был изменен с "там" на "что-то еще".

Возможно без сравнения столбцов? Есть ли какой-нибудь элегантный оператор SQL, например EXCEPT, который будет более детализированным, чем просто строка?

Спасибо.

Ответы [ 6 ]

9 голосов
/ 26 января 2010

Нет специального оператора, который можно было бы запустить, который бы точно указывал, какие столбцы изменились, но, тем не менее, запрос написать несложно:

DECLARE @Updates TABLE
(
    OldFoo varchar(50),
    NewFoo varchar(50),
    OldBar varchar(50),
    NewBar varchar(50)
)

UPDATE FooBars
SET <some_columns> = <some_values>
OUTPUT deleted.foo, inserted.foo, deleted.bar, inserted.bar INTO @Updates
WHERE <some_conditions>

SELECT *
FROM @Updates
WHERE OldFoo != NewFoo
OR OldBar != NewBar

Если вы пытаетесь на самом деле сделать что-то в результате этих изменений, то лучше всего написать триггер:

CREATE TRIGGER tr_FooBars_Update
ON FooBars
FOR UPDATE AS
BEGIN
    IF UPDATE(foo) OR UPDATE(bar)
        INSERT FooBarChanges (OldFoo, NewFoo, OldBar, NewBar)
            SELECT d.foo, i.foo, d.bar, i.bar
            FROM inserted i
            INNER JOIN deleted d
                ON i.id = d.id
            WHERE d.foo <> i.foo
            OR d.bar <> i.bar
END

(Конечно, вы, вероятно, захотите сделать больше, чем это, в триггере, но есть пример очень упрощенного действия)

Вы можете использовать COLUMNS_UPDATED вместо UPDATE, но я нахожу это болезненным, и он все равно не скажет вам, какие столбцы действительно изменили , какие столбцы были включены в UPDATE заявление. Так, например, вы можете написать UPDATE MyTable SET Col1 = Col1, и он все равно скажет вам, что Col1 был обновлен, хотя на самом деле не было изменено ни одного отдельного значения. При написании триггера вам необходимо на самом деле проверить отдельные значения до и после, чтобы убедиться, что вы получаете реальные изменения (если это то, что вы хотите).

P.S. Вы также можете UNPIVOT, как говорит Роб, но вам все равно нужно явно указать столбцы в предложении UNPIVOT, это не волшебство.

2 голосов
/ 26 января 2010

Попробуйте отключить как вставленные, так и удаленные, и тогда вы сможете присоединиться, ища, где значение изменилось.

1 голос
/ 26 января 2010

Вы можете обнаружить это в триггере или использовать CDC в SQL Server 2008.

Если вы создадите триггер FOR AFTER UPDATE, то таблица inserted будет содержать строки с новыми значениями, а таблица deleted будет содержать соответствующие строки со старыми значениями.

0 голосов
/ 24 марта 2011

Альтернативный вариант для отслеживания изменений данных - записать данные в другую (возможную временную) таблицу, а затем проанализировать разницу с использованием XML. Измененные данные записываются в таблицу аудита вместе с именами столбцов. Единственное, вам нужно знать поля таблицы, чтобы подготовить временную таблицу. Вы можете найти это решение здесь:

0 голосов
/ 26 января 2010

Если вы используете SQL Server 2008, вам, вероятно, стоит взглянуть на новую функцию захвата данных изменений. Это будет делать то, что вы хотите.

0 голосов
/ 26 января 2010
OUTPUT deleted.bar AS [OLD VALUE], inserted.bar AS [NEW VALUE]

@ Calvin Я просто опирался на пример ОБНОВЛЕНИЯ. Я не говорю, что это полное решение. Я намекнул, что вы можете сделать это где-нибудь в вашем коде; -)

Так как я уже получил -1 из вышеприведенного ответа, позвольте мне добавить это:

Если вы действительно не знаете, какой столбец был обновлен, я бы сказал, создайте триггер и используйте функцию COLUMNS_UPDATED () в теле этого триггера (см. this )

Я создал в своем блоге Справочник по битовой маске для использования с этим COLUMNS_UPDATED (). Это облегчит вашу жизнь, если вы решите пойти по этому пути (Trigger + Columns_Updated ())

Если вы не знакомы с Trigger, вот мой пример базового Trigger http://dbalink.wordpress.com/2008/06/20/how-to-sql-server-trigger-101/

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...