sql >> Database >  >> RDS >> Oracle

IF EXISTS (SELECT ...) gebruiken in een BEFORE INSERT-trigger (Oracle)

Ten eerste, als u SQL*Plus gebruikt, wanneer u een object maakt en u wordt verteld dat er compilatiefouten zijn, het commando show errors zal u de fouten tonen.

Als je show errors hebt uitgevoerd , zou je te horen krijgen dat IF EXISTS is geen geldige syntaxis. Je zou zoiets kunnen doen als

SELECT COUNT(*)
  INTO l_cnt
  FROM <<rest of query>>

IF( l_cnt > 0 )
THEN
  RAISE_APPLICATION_ERROR ...
END IF;

Zodra u de compilatiefout hebt opgelost, krijgt u echter runtime-fouten. In een trigger op rijniveau op surveillance , kunt u in het algemeen geen query uitvoeren op surveillance (u kunt als alles wat u doet een INSERT VALUES is dat gegarandeerd slechts één rij invoegt). Als u dit doet, krijgt u tijdens runtime een muterende triggerfout.

Vanuit het perspectief van een gegevensmodel, wanneer u merkt dat u een tabel ontwerpt waarin de geldige gegevens voor een bepaalde rij afhankelijk zijn van gegevens die zijn opgeslagen in andere rijen van dezelfde tabel, heeft u over het algemeen de normalisatieprincipes geschonden en bent u over het algemeen beter af met het oplossen van de onderliggend datamodel.

Als je echt vastbesloten bent om het gegevensmodel te behouden, zou ik er de voorkeur aan geven een gematerialiseerde weergave te maken die wordt vernieuwd bij de vastlegging en die alleen gegevens bevat voor rijen die in strijd zijn met je criteria. Je kunt dan beperkingen opleggen aan die gematerialiseerde weergave die fouten veroorzaakt op het moment van commit wanneer je criteria worden geschonden. Dit vereist gematerialiseerde weergavelogboeken op uw tafel.

Als je het datamodel echt wilt behouden en de logica met triggers wilt afdwingen, heb je de klassieke drie-trigger-oplossing nodig (of een samengestelde trigger met drie delen als je 11.2 of hoger gebruikt). U zou een pakket maken met een verzameling primaire sleutelwaarden. Een trigger voor de instructie zou de verzameling initialiseren. Een trigger op rijniveau zou de primaire sleutels invoegen van de rijen die in deze verzameling zijn ingevoegd en/of bijgewerkt. En dan zou een trigger na de instructie deze verzameling herhalen en alle controles uitvoeren die u maar wilt. Dat zijn echter veel ontroerende stukken, daarom raad ik het over het algemeen af.

En zelfs als je al deze onderdelen werkend krijgt, zal je logica je niet beschermen in een omgeving met meerdere gebruikers. Als je meerdere gebruikers tegelijkertijd op het systeem hebt, is het heel goed mogelijk dat de ene gebruiker een rij invoegt, de tweede gebruiker een andere rij met een overlappend bereik, en dan zal elke sessie zich committen. In dat geval staan ​​beide sets triggers de wijziging toe, maar blijven er gegevens in de tabel over die in strijd zijn met uw vereisten. De gematerialiseerde weergave, omdat deze wordt afgedwongen tijdens de commit-tijd in plaats van op het moment van de invoeging, zal correct werken in een omgeving met meerdere gebruikers. Als u wilt dat de triggers werken in een omgeving met meerdere gebruikers, moet u ze nog ingewikkelder maken door extra logica toe te voegen die serialisatie afdwingt die de insert van de tweede sessie zou blokkeren van hardlopen tot de eerste sessie, ofwel vastgelegd of teruggedraaid. Dat voegt complexiteit toe, vermindert de schaalbaarheid en kan, afhankelijk van hoe het wordt geïmplementeerd, zorgen voor een nachtmerrie voor ondersteuning.




  1. Hoe kan ik een dynamische WHERE-clausule maken?

  2. Buitenlandse sleutels moeten Index zijn in mySQL?

  3. converteer datum naar geheel getal in postgresql

  4. Wat is de beste manier om een ​​enorme hoeveelheid gegevens in PostgreSQL te laden?