Определить строку как имеющую изменения, исключая изменения в определенных столбцах

В рамках наших бизнес-правил нам нужно отслеживать, когда строка помечается как изменяемая. Таблица содержит несколько столбцов, обозначенных как нерелевантные для наших бизнес-целей (например, поле ввода даты, отметка времени, поле проверенных битов или поле полученных битов). В таблице много столбцов, и я пытаюсь найти элегантный способ определить, изменилось ли какое-либо из соответствующих полей, а затем записать запись в таблицу аудита (ввод значения PK строки - PK не может быть отредактирован). Мне даже не нужно знать, какой столбец на самом деле изменился (хотя было бы неплохо в будущем).

Я могу выполнить это с помощью хранимой процедуры, но это некрасивый SP, использующий следующий синтаксис для обновления (операторы OR значительно сокращены для публикации):

INSERT INTO [TblSourceDataChange] (pkValue)
    SELECT d.pkValue
    FROM deleted d INNER JOIN inserted i ON d.pkValue=i.pkValue
    WHERE (    i.[F440] <> d.[F440]
          OR i.[F445] <> d.[F445]
          OR i.[F450] <> d.[F450])

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


person Penniless Tim    schedule 23.02.2011    source источник
comment
Я добавил новый ответ на этот старый вопрос, который актуален: stackoverflow.com/questions/1254787/   -  person Stephen Turner    schedule 05.11.2011


Ответы (4)


Взгляните на Change Data Capture. Это новая функция в SQL Server 2008.

Сначала вы включаете CDC в базе данных:

EXEC sys.sp_cdc_enable_db

Затем вы можете включить его для определенных таблиц и указать, какие столбцы следует отслеживать:

EXEC sys.sp_cdc_enable_table
    @source_schema = 'dbo',
    @source_name = 'xxx',
    @supports_net_changes = 1,
    @role_name = NULL, 
    @captured_column_list = N'xxx1,xxx2,xxx3'

Это создает таблицу изменений с именем cdc.dbo_xxx. Любые изменения, внесенные в записи в таблице, записываются в эту таблицу.

person TGnat    schedule 23.02.2011
comment
Это могло бы быть решением, но я действительно пытаюсь использовать методологию, в которой я указываю, какие столбцы не отслеживать (если это возможно). - person Penniless Tim; 23.02.2011
comment
Созерцание бинарной контрольной суммы или контрольной суммы-агг (но не знаком с ними, и если они будут работать) - person Penniless Tim; 23.02.2011
comment
Вы можете посмотреть Отслеживание изменений. Это похоже на сбор данных об изменениях Lite. Вам не нужно указывать какие-либо столбцы для отслеживания (я думаю), но вы получаете меньше информации об изменениях (особенно удаляет). См .: msdn.microsoft.com/en-us/library/cc280462.aspx < / а> - person TGnat; 23.02.2011
comment
CDC будет отслеживать изменения только в тех столбцах, которые вас интересуют. Если изменение произойдет в столбце, который вы не отслеживаете, вы не будете уведомлены об этом изменении. - person TGnat; 23.02.2011

Я протестую! Одно слово, которое я не могу использовать для описания доступной опции, - это элегантность. Мне еще предстоит найти удовлетворительный способ достичь того, чего вы хотите. Есть варианты, но все они немного неудовлетворительны. Когда и почему вы выбрали эти варианты, зависит от некоторых факторов, которые вы не упомянули.

  • Как часто нужно «спрашивать», какие поля изменились? То есть пользователи нечасто нажимают на ссылку «история аудита»? Или это все время, чтобы понять, как ваше приложение должно себя вести?
  • Сколько вам стоит дисковое пространство? Я не легкомыслен, но я работал там, где стратегия хранения для нашего аудита составляла проблему на миллион долларов, основанную на том, что мы платили за сан-пространство, то есть дорогое восстановление SQL-сервера не принималось во внимание, хранение размер был. Вы можете быть таким же или противоположным.

Сбор данных об изменениях

Как упоминал @TGnat, вы можете использовать CDC. Этот метод хорош, потому что вы просто включаете отслеживание изменений, а затем вызываете sproc, чтобы начать отслеживание. CDC хорош, потому что это довольно эффективное хранилище и с точки зрения мощности. Вы также как бы устанавливаете его и забываете - то есть до тех пор, пока разработчики не придут и не захотят изменить форму ваших таблиц. Для здравомыслия разработчика вам нужно сгенерировать скрипт, который отключает / включает отслеживание ваших сущностей.

Я заметил, что вы хотите исключить определенные столбцы, а не включать их. Вы можете сделать это с помощью трюка FOR XML PATH. Вы можете написать такой запрос, а затем использовать переменную @capturedColList при вызове sys.sp_cdc_enable_table ..

 SET @capturedColList =   SELECT Substring( (
                SELECT ',' + COLUMN_Name
                FROM INFORMATION_SCHEMA.COLUMNS 
                WHERE TABLE_NAME = '<YOUR_TABLE>' AND
                      COLUMN_NAME NOT IN ('excludedA', 'excludedB')

                FOR XML PATH( '' )  
            )  , 2, 8000)

Триггеры с кейсами. Второй вариант, который я вижу, - это генерация кода. Это может быть внешний жгут или SPROC, который записывает ваши триггеры. Каким бы ни был ваш яд, он должен быть автоматизированным и универсальным. Но вы, в основном, кодируете DDL для триггеров, сравнивающих текущий с INSERTED или DELETED, используя множество невыразительных операторов CASE для каждого столбца.

Здесь обсуждается стиль здесь .

Регистрировать все, разбираться позже

Последний вариант - использовать триггер для регистрации каждого изменения строки. Затем вы пишете код (SPROCS / UDF), который может просматривать данные вашего журнала и распознавать, когда произошло изменение. Почему вы выбрали этот вариант? Место на диске не имеет значения, и хотя вам нужно понимать, что изменилось, вы очень редко задаете системе этот вопрос.

HTH,

-эрик

person EBarr    schedule 24.02.2011
comment
Спасибо за информацию! Что сбивает с толку в моем вопросе, так это то, что похоже, что я проверяю изменения, а я нет (место на диске не является проблемой). Наша система рассчитывает налоговые декларации, и у нас есть таблицы, определенные как исходные данные - изменение любого из значений повлияет на расчет налога. Наша система просматривает таблицу TblSourceDataChange (она содержит дополнительные поля, не указанные в списке) и определяет вычисления с измененными исходными данными. Мы не делаем на уровне столбцов, так как вычисления очень сложны, и нам просто нужны «возможно» измененные результаты. Мы используем одну и ту же структуру таблиц каждый последующий год. - person Penniless Tim; 24.02.2011
comment
@user ‹со странными числами› - хотя ваш вариант использования отличается от того, что я упоминал выше, он звучит как журнал, и позже будет уместно разобраться в нем. Хотя непонятно, с какой периодичностью у вас меняются (ежегодно?). Я не упомянул, как разобраться в этом позже, но вы можете эффективно использовать некоторые умные предложения group by, чтобы ваш запрос генерировал отдельную строку для каждого изменения. Вы захотите автоматизировать создание этих запросов. HTH, -eric - person EBarr; 24.02.2011

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

person HLGEM    schedule 23.02.2011

Я нашел ответ в сообщении Обновление SQL Server, получить только измененные поля и адаптировал SQL под свои нужды (этот sql находится в триггере). SQL размещен ниже:

DECLARE @idTable INT SELECT @idTable = T.id FROM sysobjects P JOIN sysobjects T ON P.parent_obj = T.id WHERE P.id = @@ procid

ЕСЛИ СУЩЕСТВУЕТ (ВЫБРАТЬ * ИЗ syscolumns WHERE id = @idTable
И ПРЕОБРАЗОВАТЬ (ПЕРЕМЕННАЯ, ОБРАТНАЯ ()) И ПИТАНИЕ (ПРЕОБРАЗОВАТЬ (БОЛЬШОЙ, 2), средство цвета - 1)> 0 И имя НЕ В ('отметка времени ',' Reviewed ')) BEGIN - сделайте здесь подходящие действия END

person Penniless Tim    schedule 25.02.2011
comment
К вашему сведению: хотя функция COLUMNS_UPDATED (), кажется, указывает на то, что столбец был изменен, это не всегда верно. Это означает, что столбец был «затронут», но это вполне могло быть: UPDATE myTable SET myField = MyField. Опять же, это, вероятно, хорошее начало поверх триггера, поэтому вам не нужно искать вставку и удаление, если ни один из столбцов не был затронут. PS: ColumnsUpdated намного быстрее, чем проверка каждого столбца отдельно с помощью UPDATE ()! - person deroby; 23.05.2011