0

У меня есть странное деловое требование, которое меня озадачило. Некоторые предпосылки: в основном у меня есть две таблицы для отслеживания улучшений программы: Enhancement and Bug. Связь для улучшения -> Ошибка - 1: m, а таблица ошибок имеет столбец EnhancementID с внешним ключом.Дизайн базы данных: состояние одной таблицы на основе другой

В обеих таблицах есть столбец «Статус», но это становится сложной задачей. Мое требование состоит в том, что статус улучшения зависит от связанных с ним ошибок. Например, если у нас есть 3 ошибки с параметром EnhancementID из 100 и состояния «In Testing», то статус Enhancement 100 должен автоматически устанавливаться на «In Testing». Существует несколько правил о статусе.

Эта база данных используется несколькими приложениями, поэтому моя первая мысль заключалась в использовании триггера «On Update» в таблице Bug. Поскольку у триггера был оператор Select в таблице запуска, я получил ошибку «mutating table» (я должен запросить статусы всех ошибок с указанным EnhancementID при срабатывании триггера). Теперь я пытаюсь реализовать три триггерных решения, описанных здесь: http://asktom.oracle.com/pls/asktom/ASKTOM.download_file?p_file=6551198119097816936, но я опасаюсь вкладывать столько логики в триггеры базы данных.

Так что мой вопрос: я приближаюсь к этой проблеме разумно? Есть ли лучший способ, который кто-то мог бы предложить? Возможно, используя представление для статуса Enhancement?

ответ

5

Используйте вид.

Нет простого способа синхронизации данных по строкам/таблицам. Поскольку вы обнаружили, что триггеры приводят к ошибкам мутации и являются источником несчетных ошибок. Если вы хотите избежать ошибок при мутации, посмотрите на это workaround by Tom Kyte (это, вероятно, поможет вам понять, почему триггеры не являются лучшим инструментом в этом случае).

Вы можете использовать прикладные процедуры или API PL/SQL, но обратите внимание, что они будут работать только в том случае, если вы используете их все время (что означает, что вы никогда не выпускаете ни одного прямого обновления для этих таблиц). Один разработчик, который забывает использовать API, будет десинхронизировать ваши данные. Лично я бы рассматривал только API, если статус настолько сложный, чтобы вычислять на лету, что представление неприемлемо по производительности.

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

Если вы можете выразить свое правило в запросе SQL, это просто, например:

CREATE OR REPLACE VIEW enhancement_with_status_v AS 
SELECT e.*, 
     CASE WHEN COUNT(DECODE(b.status, 'T', 1)) >= 1 THEN 'T' 
      WHEN ... 
      ELSE ... 
     END status 
    FROM enhancement e, 
    LEFT JOIN bugs b ON b.enhancement_id = e.enhancement_id 
GROUP BY e... 

Если правила слишком сложны, вы можете написать функцию PL/SQL и вызвать эту функцию из SQL ,

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

+0

Я фактически создавал свои триггеры для предложений в этом обходном пути Тома Ките. Еще одна проблема заключается в том, что я не могу изменить приложения для использования другой таблицы из текущей таблицы Enhancement. Можно ли обновить статус таблицы Enhancement на основе этого представления? – user2811300

+0

Итак, вы пытаетесь обойти приложение с помощью триггеров, это должно быть ... неприятно! Вы можете переименовать свою таблицу и вызвать представление «повышение», но это, вероятно, вызовет больше проблем, которые он решает. Действительно, если у вас нет контроля над приложением, непредсказуемые последствия будут трудно предсказать. –

+0

Согласитесь с @VincentMalgrat - используйте представление, если можете. Триггерный подход не будет работать корректно, если у вас нет какой-либо формы блокировки (что не предусмотрено обходным решением на основе триггеров) - основная проблема заключается в том, что триггер не может «видеть» изменения, сделанные другими транзакциями (например, добавление или обновление другой ошибки со статусом «In Testing»). –

0

Нечто похожее на this может работать.

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

+0

Я думаю, что это похоже на то, что я пытался в первой попытке, где я получил ошибку «mutating table» для использования SELECT в триггере. – user2811300

+0

Если вы попытаетесь обновить таблицу b после обновления на таблице a, почему вы должны столкнуться с ошибкой мутирующей таблицы? – SriniV

+0

Потому что я должен запросить таблицу a в триггере, чтобы определить обновление состояния в таблице b. Это приводит к ошибке таблицы ошибок. – user2811300

0

Я вижу два решения для этого.

  1. триггеры базы данных, как упомянуто в вопросе
  2. Используйте приложение, чтобы обновить родительский статус (состояние усиления) вручную. Не забудьте проиндексировать внешний ключ в детском столе. В системах распределенных приложений совершенно неизбежен тупик.
+0

Спасибо, но использование приложения на самом деле не является вариантом: база данных используется совместно несколькими приложениями. – user2811300

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