For det første, hvis du bruger SQL*Plus, når du opretter et objekt og får at vide, at der er kompileringsfejl, kommandoen show errors
vil vise dig fejlene.
Hvis du kørte show errors
, vil du få at vide, at IF EXISTS
er ikke gyldig syntaks. Du kunne gøre sådan noget som
SELECT COUNT(*)
INTO l_cnt
FROM <<rest of query>>
IF( l_cnt > 0 )
THEN
RAISE_APPLICATION_ERROR ...
END IF;
Når du har rettet kompileringsfejlen, ender du dog med runtime-fejl. I en trigger på rækkeniveau på surveillance
, kan du generelt ikke forespørge surveillance
(det kan du, hvis alt du gør er en INSERT VALUES
der med garanti kun indsætter en enkelt række). Hvis du gør det, får du en muterende triggerfejl under kørsel.
Fra et datamodelperspektiv, når du finder dig selv i at designe en tabel, hvor de gyldige data for en bestemt række afhænger af data gemt i andre rækker i samme tabel, har du generelt overtrådt normaliseringsprincipperne, og du er generelt bedre tjent med at rette underliggende datamodel.
Hvis du virkelig er fast besluttet på at beholde datamodellen, vil jeg foretrække at oprette en materialiseret visning, der opdateres ved commit, som kun har data for rækker, der overtræder dine kriterier. Du kan derefter sætte begrænsninger på den materialiserede visning, der giver fejl på commit-tidspunktet, når dine kriterier er overtrådt. Dette vil kræve materialiserede visningslogfiler på dit bord.
Hvis du virkelig vil beholde datamodellen, og du vil håndhæve logikken med triggere, skal du bruge den klassiske tre-trigger-løsning (eller en sammensat trigger med tre dele, hvis du bruger 11.2 eller nyere). Du skal oprette en pakke med en samling af primære nøgleværdier. En før-sætningsudløser vil initialisere samlingen. En trigger på rækkeniveau ville indsætte de primære nøgler for de rækker, der blev indsat og/eller opdateret i denne samling. Og så ville en after statement-trigger gentage denne samling og implementere de kontroller, du ønsker. Det er dog mange bevægelige brikker, hvorfor jeg generelt fraråder det.
Plus, selvom du får alle disse dele til at fungere, vil din logik ikke beskytte dig i et flerbrugermiljø. Når du har flere brugere, der rammer systemet på samme tid, er det fuldstændig muligt, at én bruger indsætter en række, den anden bruger vil indsætte en anden række med et overlappende interval, og så vil hver session commit. I så fald vil begge sæt triggere tillade ændringen, men du vil stadig stå tilbage med data i tabellen, der overtræder dine krav. Den materialiserede visning, da den håndhæves på commit-tidspunktet snarere end på tidspunktet for indsættelsen, vil fungere korrekt i et flerbrugermiljø. Hvis du ønsker, at triggerne skal fungere i et flerbrugermiljø, skal du komplicere dem yderligere ved at tilføje yderligere logik, der gennemtvinger serialisering, der ville blokere den anden sessions insert
fra at løbe til den første session enten forpligtet eller rullet tilbage. Det tilføjer kompleksitet, reducerer skalerbarhed, og afhængigt af hvordan det implementeres, kan det give et supportmareridt.