Отслеживание измененных полей без ведения истории - PullRequest
0 голосов
/ 16 февраля 2012

У меня есть таблица с именем Books, которая содержит несколько столбцов.

ColumnNames: BookId, BookName, BookDesc, xxx

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

Каков наилучший способ достичь этого?

1) Создать таблицу Книг как:

ColumnNames: BookId, BookName, BookName_Changed_Flag, BookDesc, BookDesc_Changed_Flag, 
xxx, xxx_Changed_Flag?

2) Создайте отдельную таблицу Books_Change_Log точно так же, как таблицу Books, но только со столбцами изменения дорожки, как:

ColumnNames: BookId, BookName_Changed_Flag, BookDesc_Changed_Flag, xxx_Changed_Flag?

Пожалуйста, сообщите.

- Обновление -

В каждой таблице более 20 столбцов. И каждый столбец представляет определенный элемент в пользовательском интерфейсе. Если значение столбца когда-либо изменяется по сравнению с его исходной записью, мне нужно отобразить элемент пользовательского интерфейса, который представляет значение столбца в другом стиле. Остальные элементы должны выглядеть нормально.

Ответы [ 5 ]

2 голосов
/ 16 февраля 2012

Как использовать битовое поле в TSQL (для обновлений и чтений)

Установите битовое поле по умолчанию равным 0 при запуске (то есть без изменений), вы должны использовать тип int для максимум 32 бит данных и bigintдо 64 бит данных.

Чтобы установить бит в битовом поле, используйте | (оператор ИЛИ в битах) в операторе обновления, например,

UPDATE table 
SET field1 = 'new value', bitfield = bitfield | 1

UPDATE table 
SET field2 = 'new value', bitfield = bitfield | 2

и т. д. дляв каждом поле используется значение от 2 до степени N-1 для значения после |

. Для чтения битового поля используйте & (оператор бита И) и посмотрите, является ли оно истинным, например,

SELECT field1, field2,
       CASE WHEN (bitfield & 1) = 1 THEN 'field1 mod' ELSE 'field1 same' END,
       CASE WHEN (bitfield & 2) = 2 THEN 'field2 mod' ELSE 'field2 same' END
FROM table

примечание. Я бы, вероятно, не использовал текст, поскольку он будет использоваться приложением, что-то вроде этого будет работать

SELECT field1, field2,
        CASE WHEN (bitfield & 1) = 1 THEN 1 ELSE 0 END AS [field1flag],
        CASE WHEN (bitfield & 2) = 2 THEN 1 ELSE 0 END AS [field2flag]
FROM table

или вы можете использовать! = 0 выше, чтобы сделать его простым какЯ сделал в моем тесте ниже


Необходимо провести тестирование, чтобы не было ошибок, щелкните для сценария тестирования


оригинальный ответ:

Если в вашей таблице меньше 16 столбцов, вы можете сохранить «флаги» как целое число, а затем использовать битовый флаг mметод для обозначения столбцов, которые изменились.Просто игнорируйте или не потрудитесь пометить те, которые вас не интересуют.

Таким образом, если флаговое поле BOOLEAN AND 2 ^ N истинно, это означает, что N-е поле изменилось.

Илипример для максимального значения N = 2

0 - ничего не изменилось (все биты 0)

1 - поле 1 изменено (первый бит 1)

2 - поле 2 изменено(второй бит 1)

3 - поле 1 + 2 изменено (первый и второй бит 1)

см. эту ссылку для лучшего определения: http://en.wikipedia.org/wiki/Bit_field

1 голос
/ 16 февраля 2012

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

1 голос
/ 16 февраля 2012

Я знаю, вы сказали, что вам это не нужно, но иногда просто проще использовать что-то с полки, которое делает все, например: http://autoaudit.codeplex.com/

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

1 голос
/ 16 февраля 2012

У вас должна быть таблица журнала, в которой хранится BookId и дата изменения (вам не нужны эти другие столбцы - как вы заявили, вам не нужны старые и новые значения, и вы всегда можете получитьтекущее значение для имени, описания и т. д. из таблицы «Книги», нет причин хранить его дважды).Если вы не заинтересованы только в последний раз, когда он изменился.Вы можете заполнить таблицу журнала простым триггером обновления таблицы таблиц.Например, с новой предоставленной вами информацией:

CREATE TABLE dbo.BookLog
(
  BookID INT PRIMARY KEY,
  NameHasChanged BIT NOT NULL DEFAULT 0,
  DescriptionHasChanged BIT NOT NULL DEFAULT 0
  --, ... 18 more columns
);

CREATE TRIGGER dbo.CreateBook
ON dbo.Books FOR INSERT
AS
BEGIN
    SET NOCOUNT ON;

    INSERT dbo.BookLog(BookID) SELECT BookID FROM inserted;
END
GO

CREATE TRIGGER dbo.ModifyBook
ON dbo.Books FOR UPDATE
AS
BEGIN
    SET NOCOUNT ON;

    UPDATE t SET 
        t.NameChanged = CASE WHEN i.name <> d.name 
          THEN 1 ELSE t.NameChanged END,
        t.DescriptionChanged = CASE WHEN i.description <> d.description 
          THEN 1 ELSE t.DescriptionChanged END,
           --, 18 more of these assuming all can be compared with simple <> ...
    FROM dbo.BookLog AS t
    INNER JOIN inserted AS i ON i.BookID = t.BookID
    INNER JOIN deleted AS d  ON d.BookID = i.BookID;
END
GO
0 голосов
/ 16 февраля 2012

Поместите два столбца даты и времени в вашу таблицу, «create_at» и «updated_at». По умолчанию оба значения current_timestamp. Всегда устанавливайте значение updated_at, если вы изменяете данные в строке. Вы можете применить это с помощью триггера в таблице, который проверяет, изменяется ли какое-либо из значений столбца, а затем обновляет «updated_at», если это так.

Если вы хотите проверить, изменилась ли когда-либо строка, просто проверьте, обновлен ли он_ут> создан_ат.

...