Първо, ако използвате 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 или по-нова версия). Ще създадете пакет с колекция от стойности на първичен ключ. Тригерът преди изявление ще инициализира колекцията. Тригер на ниво ред би вмъкнал първичните ключове на редовете, които са били вмъкнати и/или актуализирани в тази колекция. И след това тригерът след изявление ще повтори тази колекция и ще приложи каквито проверки искате. Това обаче са много движещи се парчета, поради което обикновено не ги съветвам.
Освен това, дори ако накарате всички тези части да работят, вашата логика няма да ви защити в среда с много потребители. Когато имате няколко потребителя, които влизат в системата едновременно, е напълно възможно един потребител да вмъкне ред, вторият потребител да вмъкне друг ред с припокриващ се диапазон и след това всяка сесия да се ангажира. В този случай и двата набора от тригери ще позволят промяната, но пак ще останете с данни в таблицата, които нарушават вашите изисквания. Материализираният изглед, тъй като се прилага по време на предаване, а не по време на вмъкване, ще работи правилно в среда с много потребители. Ако искате тригерите да работят в среда с много потребители, ще трябва да ги усложните допълнително, като добавите допълнителна логика, която налага сериализация, която ще блокира insert
на втората сесия от стартиране до първата сесия, която е ангажирана или отменена. Това добавя сложност, намалява скалируемостта и в зависимост от това как е внедрено, може да създаде кошмар за поддръжката.