Oracle рассчитывает среднее значение с помощью триггера - PullRequest
2 голосов
/ 04 мая 2011

Для школьного проекта мы вынуждены иметь избыточную информацию и обновлять ее с помощью триггеров.У нас есть таблица с названием «recipe_ratings», которая содержит «рейтинг» (цифры 0-100).В нашей таблице «рецепты» у нас есть избыточная строка с названием «рейтинг», которая содержит среднюю оценку для этого конкретного рецепта.

Мы попытались создать триггер Oracle следующим образом:

CREATE OR REPLACE TRIGGER trigger_rating 
AFTER UPDATE 
  ON recipe_ratings 
  FOR EACH ROW

DECLARE 
  average_rating NUMBER;

BEGIN
  SELECT ROUND(AVG(rating))
  INTO average_rating
  FROM recipe_ratings
  WHERE rid = :new.rid;

  UPDATE recipe SET rating = average_rating
  WHERE rid = :new.rid 

END;

Но это дает нам: ORA-04091: имя таблицы меняется, триггер / функция может его не видеть.Мы экспериментируем с «автономной транзакцией», но кажется, что мы отдаляемся от нашего триггера.

Как мы можем заставить этот триггер работать?

Ответы [ 3 ]

4 голосов
/ 04 мая 2011

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

В реальном мире, чтобы такие вещи работали, вам нужно

  • Пакет с набором значений RID
  • Триггер оператора before, который инициализирует эту коллекцию
  • Триггер уровня строки, который вставляет значения: new.rid в коллекцию
  • Триггер оператора after, который читает коллекцию и выпускает обновления в таблице RECIPE_RATINGS

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

Если вам нужно было обрабатывать только вставки, и вы могли гарантировать, что все вставки будут вставками из одной строки, используя INSERT ... VALUES, вы можете запросить таблицу RECIPE_RATINGS в своем запросе. Это не работает в реальном мире, но этого может быть достаточно в классе.

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

2 голосов
/ 04 мая 2011

Насколько гибка ваша модель данных?

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

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

Триггер обновления добавил бы разницу между значениями: NEW и: OLD к общей сумме (и не обновил счет).

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

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

1 голос
/ 04 мая 2011

Эта статья дает один из способов избежать этих ошибок.

Другая мысль - будет ли более подходящим здесь «нормальный» триггер, чем триггер FOR EACH ROW? Если в одном операторе есть несколько обновлений recipe_rating для одного и того же рецепта, вы вычисляете среднее значение несколько раз в противном случае (отсюда и предупреждение о мутации).

...