Таблица students является изменяющейся только для строкового триггера. Это означает, что в строковом триггере обратиться к ней с запросом нельзя, но это можно сделать в операторном триггере. Однако просто взять и преобразовать триггер LimitMajors в операторный нельзя, поскольку в теле триггера используется значение : new. major. Эту проблему можно решить, если создать два триггера - строковый и операторный. В строковом триггере будет записываться значение : new. major, но таблица students запрашиваться не будет. Этот запрос будет выполняться в операторном триггере, причем будет использоваться значение, записанное в строковом триггере.
Как записать это значение? Одним из способов является применение таблицы PL/SQL внутри программного модуля. При этом можно сократить число значений, обрабатываемых во время каждой операции обновления данных. Кроме того, для каждого соединения создается свой собственный экземпляр модульных переменных, поэтому не надо беспокоиться о том, как будет выполняться обновление информации одновременно различными соединениями. Такой метод реализуется при помощи модуля student_data и триггеров RLimitMajors и SLimitmajors:
Внимание
Перед запуском приведенного выше сценария обязательно удалите неверный триггер LimitMajors.
Теперь можно проверить работу этих триггеров. Будем обновлять таблицу students до тех пор, пока не окажется слишком много студентов, профилирующей дисциплиной которых является история:
Итак, получен нужный результат. Такой метод может применяться при возникновении ошибки ORA-4091, когда строковый триггер считывает или модифицирует информацию изменяющейся таблицы. Вместо некорректного строкового триггера для обработки данных используется правильный операторный триггер AFTER. Для хранения модифицированных строк служат модульные таблицы PL/SQL.
При анализе этого примера необходимо обратить внимание на
следующее:
• Таблицы PL/SQL содержатся в модуле, поэтому они будут видимы как строковому, так и операторному триггеру. Единственным способом, гарантирующим то, что используемые переменные будут глобальными, является размещение их в модуле.
• Здесь используется переменная-счетчик StudentData. vNumEntries. При создании модуля ей присваивается начальное значение 0, которое затем увеличивается строковым триггером. Операторный триггер обращается к этой переменной и после обработки сбрасывает
ее в нуль, чтобы для следующего оператора UPDATE, выполняемого соединением, применялось корректное значение.
• Проверка максимального числа студентов, занимающихся определенной дисциплиной, немного изменена в SLimitMajors. Дело в том, что теперь это операторный триггер AFTER, и в v_CurrentStudents будет храниться число студентов, которое получено не до, а после выполнения операции ввода или обновления данных. Именно поэтому проверка числа v_CurrentStudents + 1, выполняемая в триггере LimitMajors, заменена проверкой v_CurrentStudents.
Вместо таблицы PL/SQL можно было бы воспользоваться таблицей базы данных. Автор не рекомендует этого делать, поскольку соединения, одновременно выполняющие операторы UPDATE, могут мешать работе друг друга (в Огас1е8г и выше можно применять временные таблицы). Модульные таблицы PL/SQL являются уникальными для сеансов, и с их помощью можно избежать возникновения таких проблем.
Итоги
Триггеры являются важным элементом PL/SQL и Oracle. Их можно использовать для реализации более сложных ограничений данных, чем обычные ограничения ссылочной целостности. В Oracle8 г функции триггеров расширены, они активизируются не только операциями DML, выполняемыми над таблицами и представлениями, но и различными событиями. В заключительной главе рассматриваются некоторые более сложные средства PL/SQL.
В главах с 3 по 11 рассматривались базовые возможности PL/SQL. В этой главе кратко обсуждается ряд развитых средств. Дополнительную информацию об этих средствах можно найти в книге "Огас1е8г: новые возможности программирования на языке PL/SQL" (изд. "Лори") и в документации Oracle.
< Предыдущая | Следующая > |
---|