Модераторы: Akella
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Версионность записей, Хранение истории изменений данных 
V
    Опции темы
Gluttton
Дата 28.10.2009, 00:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Начинающий
***


Профиль
Группа: Завсегдатай
Сообщений: 1170
Регистрация: 28.8.2008
Где: Феодосия

Репутация: 7
Всего: 54



Доброго времени суток!

Вдохновившись статьей на RSDN'е, решил попробовать реализовать версионность средствами Firebird.

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

Мультики начались при попытке осуществить предложенным в статье методом версионирование при удалении данных.
Автор статьи предлогает ввести дополнительное поле - флаг удаления и при удалении записи запрещать удаление записи, а вместо этого поднимать флаг (например значением IsDeleted).

Проблема в том, что как я не пытался я не смог создать триггер, который одновременно и запрещал удаление и в тоже время вносил какие либо изменения в БД. Т.о. прихожу к выводу, что реализовать в Firebird модель версионирования, при которой бы удаление заменялось на изменение флага (признака) удаления не получится. Вижу несколько вариантов. Например можно все DELET'ы записей заменить на их UPDATE'ы... Но мне это не совсем нравится (почему то). Второй вариант заключается в том, что бы для удаленных записей создать отдельную таблицу, и при удалении переносить запись из таблицы неудаленных данных в таблицу удаленных.

Вопросы: хотелось бы услышать, приходилось ли кому сталкиваться с версионированием и как это было реализовано?


--------------------
Слава Україні!
PM MAIL   Вверх
Deniz
Дата 28.10.2009, 06:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1251
Регистрация: 16.10.2004
Где: Новый Уренгой

Репутация: 22
Всего: 44



Один из вариантов, создать вьюшку на таблицу (запретить весь доступ к таблице), на нее триггеры, и в триггере можно делать что угодно. В других СУБД такие триггеры называются "instead of" (вроде пока таких в FB нет, поправьте если не так)
Второй вариант, завернуть все операции в хранимые процедуры.


--------------------
"Для того чтобы сделать шаг вперед, достаточно пинка сзади" (с)
PM ICQ   Вверх
Akella
Дата 28.10.2009, 16:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

Репутация: 20
Всего: 329



Цитата(Gluttton @  28.10.2009,  00:49 Найти цитируемый пост)
Проблема в том, что как я не пытался я не смог создать триггер, который одновременно и запрещал удаление и в тоже время вносил какие либо изменения в БД. 

Почему не мог создать такой триггер?
PM MAIL   Вверх
Gluttton
Дата 28.10.2009, 18:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Начинающий
***


Профиль
Группа: Завсегдатай
Сообщений: 1170
Регистрация: 28.8.2008
Где: Феодосия

Репутация: 7
Всего: 54



Цитата(Akella @  28.10.2009,  16:49 Найти цитируемый пост)
Почему не мог создать такой триггер?

Если коротко, то... Что бы отменить удаления я должен сгенерировать исключение, при вызове исключения, если его не обработать, все операции выполненные в триггере откатываются (т.е. нет возможности внести updeate флага признака удаления), а если обработать исключение, то удаление не отменяется (т.е. происходит удаление той(тех) записей для которых вызван delete)...

Пытался разнести операции отмены удаления и обновления флага по триггерам before- и after- , но безрезультатно. На сколько я понял, то причина в том, что триггер after- не видит запись, которая удаляется.

Это сообщение отредактировал(а) Gluttton - 28.10.2009, 18:47


--------------------
Слава Україні!
PM MAIL   Вверх
Akella
Дата 28.10.2009, 21:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

Репутация: 20
Всего: 329



Ну да, я так и предполагал.
PM MAIL   Вверх
Gluttton
Дата 28.10.2009, 22:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Начинающий
***


Профиль
Группа: Завсегдатай
Сообщений: 1170
Регистрация: 28.8.2008
Где: Феодосия

Репутация: 7
Всего: 54



Цитата(Deniz @  28.10.2009,  06:45 Найти цитируемый пост)
Второй вариант, завернуть все операции в хранимые процедуры.

Можно конечно же, но... Точно так же можно заменить удаление обновлением... Не совсем то, что хотелось бы smile, как то натянуто (хотя если по другому не получится, то очень даже вариант).

Цитата(Akella @  28.10.2009,  21:38 Найти цитируемый пост)
Ну да, я так и предполагал.

Как smile?
Цитата(Gluttton @  28.10.2009,  18:28 Найти цитируемый пост)
Пытался разнести операции отмены удаления и обновления флага по триггерам before- и after- , но безрезультатно.

Что не получится smile?

Вот как я делал...

Пусть есть таблица с исходными данными - SC:
Код

CREATE TABLE SC
(
    ID           BIGINT NOT NULL,
    FIELD        VARCHAR(50) NOT NULL,
    STATE        VARCHAR(20) NOT NULL
);

STATE - состояние ('NoD' - не удалено, 'IsD' - удалено).
Пусть нам необходимо отслеживать изменения поля FIELD, для этого есть таблица истории - HS:
Код

CREATE TABLE HS
(
    ID           BIGINT NOT NULL,
    FIELD        BIGINT NOT NULL,
    RECORD       VARCHAR(50) NOT NULL,
    ACT          VARCHAR(20) NOT NULL,
    D            DATE,
    T            TIME,
    OWNER        VARCHAR(50) NOT NULL
);

OWNER - имя пользователя, который внес изменения, D и T дата и время изменения, ACT - действие (удаление, обновление), RECORD - старое значение поля SC.FIELD, а FIELD - внешний ключ SC.ID.

Создадим триггер на обновление:
Код

SET TERM ^;

CREATE TRIGGER SC_MOD FOR SC
ACTIVE BEFORE UPDATE POSITION 1
AS
BEGIN
    INSERT INTO HS(FIELD, RECORD, ACT, D, T, OWNER)
    VALUES
    (
        OLD.ID,
        OLD.FIELD,
        'Update',
        CURRENT_DATE,
        CURRENT_TIME,
        CURRENT_USER
    );
END^

SET TERM ;^


Работает как часики smile ...

А теперь пробую создать триггеры на удаление, для этого потребуется создать исключение:
Код

CREATE EXCEPTION SC_DEL 'Deleting was canceled!';


Первый триггер:
Код

SET TERM ^;

CREATE OR ALTER TRIGGER SC_ADEL FOR SC
ACTIVE AFTER DELETE POSITION 1
AS
BEGIN
    EXCEPTION SC_DEL;
END^

SET TERM ;^


Второй триггер:
Код

SET TERM ^;

CREATE OR ALTER TRIGGER SC_BDEL FOR SC
ACTIVE BEFORE DELETE POSITION 0
AS
BEGIN
    INSERT INTO HS(FIELD, RECORD, ACT, D, T, OWNER)
    VALUES
    (
        OLD.ID,
        OLD.FIELD,
        'Delete',
        CURRENT_DATE,
        CURRENT_TIME,
        CURRENT_USER
    );
    UPDATE SC SET STATE='IsD'
    WHERE ID=OLD.ID;
END^

SET TERM ;^


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

На всякий случай скрипт тестовой БД.

Это сообщение отредактировал(а) Gluttton - 28.10.2009, 22:51

Присоединённый файл ( Кол-во скачиваний: 5 )
Присоединённый файл  TRC.sql 5,59 Kb


--------------------
Слава Україні!
PM MAIL   Вверх
Deniz
Дата 29.10.2009, 07:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1251
Регистрация: 16.10.2004
Где: Новый Уренгой

Репутация: 22
Всего: 44



Gluttton, вроде уже говорил, но повторюсь.
Цитата(Gluttton @  29.10.2009,  01:50 Найти цитируемый пост)
D и T дата и время изменения
используй одно поле в этом случае
Код
dt timestamp default current_timestamp


Добавлено через 4 минуты и 30 секунд
Gluttton, сделал у себя тест с вьюхой см. вложение. для сервера версии 1.5
Запрос во вьюхе необходимо сделать необновляемым, иначе триггер на удаление удаляет запись в таблице sc


Присоединённый файл ( Кол-во скачиваний: 7 )
Присоединённый файл  src.sql 4,11 Kb


--------------------
"Для того чтобы сделать шаг вперед, достаточно пинка сзади" (с)
PM ICQ   Вверх
Akella
Дата 29.10.2009, 11:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

Репутация: 20
Всего: 329



Цитата(Gluttton @  28.10.2009,  22:50 Найти цитируемый пост)
Ну да, я так и предполагал.

Как smile?

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

Добавлено через 1 минуту и 31 секунду
Цитата(Gluttton @  28.10.2009,  22:50 Найти цитируемый пост)
При попытке удалить запись из исходной таблицы отмена удаления срабатывает, а обновления и логгирования не происходит...

и я о том же
PM MAIL   Вверх
Gluttton
Дата 29.10.2009, 21:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Начинающий
***


Профиль
Группа: Завсегдатай
Сообщений: 1170
Регистрация: 28.8.2008
Где: Феодосия

Репутация: 7
Всего: 54



Deniz, 
Спасибо за скрипт!

Akella, 
Т.е. это безисходность?
Триггер на уделение, выполняющий любое действие вместе с отменой удаления, никак не создать?

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


--------------------
Слава Україні!
PM MAIL   Вверх
Akella
Дата 15.11.2009, 01:30 (ссылка) |    (голосов:2) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

Репутация: 20
Всего: 329



Цитата(Gluttton @  29.10.2009,  21:58 Найти цитируемый пост)
Т.е. это безисходность?

Ну в версии 2,5 ввели автономные транзакции.
Код

create table log (
  logdate timestamp,
  msg varchar(60)
);

create exception e_conn 'Connection rejected';

set term !;

create trigger t_conn on connect
as
begin
  if (current_user = 'BAD_USER') then
  begin







    in autonomous transaction
    do
    begin
      insert into log (logdate, msg) values (current_timestamp, 'Connection rejected');
    end






    exception e_conn;
  end
end!

set term ;!


PM MAIL   Вверх
Gluttton
Дата 16.11.2009, 00:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Начинающий
***


Профиль
Группа: Завсегдатай
Сообщений: 1170
Регистрация: 28.8.2008
Где: Феодосия

Репутация: 7
Всего: 54



Akella, спасибо за ценный совет smile !
Используя автономные транзакции сумел одним триггером и внести записть в таблицу истории (логов) и отменить само удаление!

Но! Изначально задумывалось так, что при удалении запись в исходной таблице не удаляется, а помечается как удаленная.
Цитата(Gluttton @  28.10.2009,  22:50 Найти цитируемый пост)
Пусть есть таблица с исходными данными - SC:
Код

CREATE TABLE SC
(
    ID           BIGINT NOT NULL,
    FIELD        VARCHAR(50) NOT NULL,
    STATE        VARCHAR(20) NOT NULL
);

STATE - состояние ('NoD' - не удалено, 'IsD' - удалено).


Так вот изменить (выполнить UPDATE) с той записью, которая удаляется никак не получается, т.к. до вызова исключения она удалена, а после вызова исключения уже ничего не выполняется...
Вот это уже безисходность smile ?


--------------------
Слава Україні!
PM MAIL   Вверх
Akella
Дата 16.11.2009, 12:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

Репутация: 20
Всего: 329



1. В автономной транзакции помечай запись, как удалённую.
2. Вызывай исключение.

В итоге, запись будет помечена, как удалённая. И удалена не будет.
PM MAIL   Вверх
Gluttton
Дата 17.11.2009, 00:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Начинающий
***


Профиль
Группа: Завсегдатай
Сообщений: 1170
Регистрация: 28.8.2008
Где: Феодосия

Репутация: 7
Всего: 54



Akella,  smile , я так думаю, бубен на аватар нужно было тебе поставить, а не мне smile !

Ну честное слово вчера пробовал, не получалось! Сегодня, хотел повторить, что бы всё грамотно описать, что не получается, а тут бац - и всё работает!

Итак по сути...
Тема закрыта smile, спасибо всем!

Для тех, кого в эту ветку приведет поиск, выкладываю конечный вариант скрипта для Firebird 2.5 (не эталон, но для примера, думаю, сгодится smile ).

Присоединённый файл ( Кол-во скачиваний: 16 )
Присоединённый файл  TRC.sql 5,43 Kb


--------------------
Слава Україні!
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Interbase"
Alex

Обязательно указание:

1. Версию InterBase (Firebird, Yaffil)

2. Способа доступа (ADO, BDE, IBX и т.д.)

  • КАК ПРАВИЛЬНО ОФОРМИТЬ КОД - ЗДЕСЬ
  • КАК ПРАВИЛЬНО УКАЗАТЬ ТЕКСТ ОШИБКИ - ЗДЕСЬ
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • FAQ раздела лежит здесь!

Если Вам понравилась атмосфера форума, заходите к нам чаще! С Уважением, Akella.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Firebird, Interbase | Следующая тема »


 




[ Время генерации скрипта: 0.0849 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.