2010-08-09 3 views
2

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

CREATE OR REPLACE TRIGGER mySchema.trg_projectHistory 
BEFORE UPDATE OR DELETE 
ON mySchema.projects REFERENCING NEW AS New OLD AS Old 
FOR EACH ROW 
declare tmpVersion number; 
BEGIN 
    select myPackage.GETPROJECTVERSION(:OLD.project_ID) into tmpVersion from dual; 

    INSERT INTO mySchema.projectHistiry 
    (project_ID, ..., version) 
    VALUES 
    (:OLD.project_ID, 
    ... 
    tmpVersion 
    ); 

EXCEPTION 
WHEN OTHERS THEN 
    -- Consider logging the error and then re-raise 
    RAISE; 
END ; 
/

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

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

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

Если я изменяю триггеры для ввода в 3 таблицы для первого примера, тогда у меня будет 9 вставок, когда произойдет второй пример.

Не совсем уверен, как это решить. любая помощь?

ответ

0

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

Например. В таблице Project_hist были бы eff_date и exp_date, у которых есть дата начала и окончания для данного проекта. В таблице проекта будет только дата вступления в силу. (так как это активный проект).

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

+0

true, но другой задачей, с которой я сталкиваюсь, теперь является история задач, но не история проекта/клиента. Мне нужно выяснить соединение: если в x_history ничего нет, то получите его от x. – CFNinja

+0

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

+0

Таблицы истории содержат только неактивные версии. Любое обновление/удаление на любые основные таблицы создает неактивные версии истории. Как сделать последнее? Если в x_history ничего нет, перейдите к нему из x. – CFNinja

2

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

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

Упакованная процедура вставляет во все три таблицы истории соответствующий проект, клиент и задачи, где еще нет записи истории для этого ключа и транзакции (т. Е. Вы не хотите дублировать). У вас есть несколько вариантов, когда дело доходит до последнего. Вы можете использовать уникальное ограничение и выбрать BULK и вставить с помощью FORALL/SAVE EXCEPTIONS, DML регистрации ошибок (EXCEPTIONS INTO) или INSERT ... SELECT ... WHERE NOT EXISTS ...

Вам необходимо отслеживайте свои транзакции. Я предполагаю, что это то, что вы делали с myPackage.GETPROJECTVERSION. Хитрость здесь заключается в том, чтобы увеличивать версии только при наличии новой транзакции. Если, когда вы получаете новый номер версии, вы держите его в переменной уровня pacakge, вы можете легко определить, имеет ли ваш сеанс уже номер версии или нет.

Если сеанс будет запускать несколько транзакции, вам необходимо «ясно» из номера версии сеансового уровня, если она была частью предыдущей сделки. Если вы получаете DBMS_TRANSACTION.LOCAL_TRANSACTION_ID и хранить, что на уровне пакета/сессии, а также, вы можете определить, если вы находитесь в новой транзакции, или часть одной и той же сделки.

+0

+1 для диагностики варианта использования, лежащего в основе вопроса – APC

+0

Я думаю, что вы захотите сделать «слияние» для последующих изменений в той же транзакции. Если вы используете 'not exist', вы получите моментальный снимок, содержащий первоначальные изменения в одной таблице, и проигнорируйте остальные два (а также последующие изменения в первой таблице в рамках одной транзакции). – Allan

0

Альтернативный ответ. Посмотрите на Total Recall/Flashback Archive Вы можете установить сохранение на 10 лет и использовать простой AS TIMESTAMP для получения данных по любой конкретной отметке времени.

Не уверен в отношении производительности. Может быть проще иметь ежедневное или еженедельное сохранение, а затем отдельное запланированное задание, которое выбирает старые версии с использованием синтаксиса VERSIONS BETWEEN и сохраняет их в вашей таблице истории.

+0

Если у вас есть деньги на лицензии, то Total Recall определенно является самым элегантным решением. – APC

Смежные вопросы