Во-первых, если вы используете SQL*Plus, когда вы создаете объект и получаете сообщение об ошибках компиляции, команда show errors
покажет вам ошибки.
Если вы запустите show errors
, вам сообщат, что IF EXISTS
недопустимый синтаксис. Вы можете сделать что-то вроде
SELECT COUNT(*)
INTO l_cnt
FROM <<rest of query>>
IF( l_cnt > 0 )
THEN
RAISE_APPLICATION_ERROR ...
END IF;
Однако, как только вы исправите ошибку компиляции, вы получите ошибки времени выполнения. В триггере уровня строки для surveillance
вы обычно не можете запрашивать surveillance
(можно, если все, что вы делаете, это INSERT VALUES
, который гарантированно вставит только одну строку). Если вы это сделаете, вы получите ошибку мутирующего триггера во время выполнения.
С точки зрения модели данных, когда вы проектируете таблицу, в которой действительные данные для конкретной строки зависят от данных, хранящихся в других строках той же таблицы, вы, как правило, нарушаете принципы нормализации, и вам, как правило, лучше исправить ошибку. базовая модель данных.
Если вы действительно полны решимости сохранить модель данных, я бы предпочел создать материализованное представление, которое обновляется при фиксации и имеет данные только для строк, которые нарушают ваши критерии. Затем вы можете наложить ограничения на это материализованное представление, которые выдают ошибки во время фиксации, когда ваши критерии нарушаются. Для этого потребуются материализованные журналы просмотра на вашем столе.
Если вы действительно хотите сохранить модель данных и применить логику с помощью триггеров, вам понадобится классическое решение с тремя триггерами (или составной триггер с тремя частями, если вы используете 11.2 или более позднюю версию). Вы бы создали пакет с набором значений первичного ключа. Триггер оператора before инициализирует коллекцию. Триггер уровня строки будет вставлять первичные ключи строк, которые были вставлены и/или обновлены в эту коллекцию. И затем триггер оператора after будет перебирать эту коллекцию и выполнять любые проверки, которые вы хотите. Однако это много движущихся частей, поэтому я обычно не советую этого делать.
К тому же, даже если вы заставите все эти части работать, ваша логика не защитит вас в многопользовательской среде. Когда к системе одновременно обращаются несколько пользователей, вполне возможно, что один пользователь вставит строку, второй пользователь вставит другую строку с перекрывающимся диапазоном, а затем каждый сеанс будет зафиксирован. В этом случае оба набора триггеров разрешат изменение, но вы все равно останетесь с данными в таблице, которые нарушают ваши требования. Поскольку материализованное представление применяется во время фиксации, а не во время вставки, оно будет правильно работать в многопользовательской среде. Если вы хотите, чтобы триггеры работали в многопользовательской среде, вам придется еще больше усложнить их, добавив дополнительную логику, обеспечивающую сериализацию, которая блокирует запуск второго сеанса insert
до тех пор, пока первый сеанс не будет зафиксирован или откатан. Это добавляет сложности, снижает масштабируемость и, в зависимости от того, как это реализовано, может превратить поддержку в кошмар.
person
Justin Cave
schedule
28.03.2014
show errors
, если ваш клиент поддерживает это, илиselect * from user_errors where type = 'TRIGGER' and name = 'CHEV_SURV'
. Это доступно для любого сохраненного PL/SQL. Вы правы, вы не можете использоватьexists
вне условияselect
. Но даже если вы скомпилируете его, вы получите ошибку мутирующей таблицы — вы не можете запросить таблицу, против которой работает триггер. - person Alex Poole   schedule 28.03.2014select ... from ... where exists (select ... from ...)
. Ответ Джастина показывает вам, как вы должны проверить в этом случае и почему это все еще не сработает * 8-) - person Alex Poole   schedule 28.03.2014