sql >> Databasteknik >  >> RDS >> Oracle

Använda IF EXISTS (SELECT ...) i en BEFORE INSERT-utlösare (Oracle)

För det första, om du använder SQL*Plus, när du skapar ett objekt och får veta att det finns kompileringsfel, kommandot show errors kommer att visa dig felen.

Om du körde show errors , du skulle få veta att IF EXISTS är inte giltig syntax. Du kan göra något liknande

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

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

När du åtgärdat kompileringsfelet kommer du dock att sluta med körtidsfel. I en utlösare på radnivå på surveillance , kan du i allmänhet inte fråga surveillance (det kan du om allt du gör är en INSERT VALUES som garanterat bara infogar en enda rad). Om du gör det kommer du att få ett muterande triggerfel vid körning.

Ur ett datamodellperspektiv, när du kommer på dig själv med att designa en tabell där giltiga data för en viss rad beror på data lagrade i andra rader i samma tabell, har du i allmänhet brutit mot normaliseringsprinciperna och du är generellt sett bättre värd att fixa underliggande datamodell.

Om du verkligen är fast besluten att behålla datamodellen, skulle jag föredra att skapa en materialiserad vy som uppdateras vid commit som endast har data för rader som bryter mot dina kriterier. Du kan sedan sätta begränsningar på den materialiserade vyn som ger fel vid beställningstidpunkten när dina kriterier överträds. Detta kräver materialiserade vyloggar på ditt bord.

Om du verkligen vill behålla datamodellen och du vill genomdriva logiken med triggers, skulle du behöva den klassiska tretriggerlösningen (eller en sammansatt trigger med tre delar om du använder 11.2 eller senare). Du skulle skapa ett paket med en samling primära nyckelvärden. En before-utlösare skulle initiera samlingen. En utlösare på radnivå skulle infoga primärnycklarna för raderna som infogades och/eller uppdaterades i denna samling. Och sedan skulle en efter-utlösare upprepa den här samlingen och implementera vilka kontroller du vill. Det är dock många rörliga pjäser, varför jag generellt avråder från det.

Plus, även om du får alla dessa delar att fungera, kommer din logik inte att skydda dig i en miljö med flera användare. När du har flera användare som träffar systemet samtidigt är det fullt möjligt att en användare infogar en rad, den andra användaren kommer att infoga en annan rad med ett överlappande intervall, och sedan kommer varje session att commit. I så fall kommer båda uppsättningarna av utlösare att tillåta ändringen, men du kommer fortfarande att ha data i tabellen som bryter mot dina krav. Den materialiserade vyn kommer att fungera korrekt i en miljö med flera användare, eftersom den tillämpas vid commit-tid snarare än vid tidpunkten för insättningen. Om du vill att triggers ska fungera i en miljö med flera användare, måste du komplicera dem ytterligare genom att lägga till ytterligare logik som tvingar fram serialisering som skulle blockera den andra sessionens insert från att springa tills den första sessionen antingen har begåtts eller rullats tillbaka. Det ökar komplexiteten, minskar skalbarheten och beroende på hur det implementeras kan det bli en mardröm för support.




  1. jQuery Plugin för att uppdatera live a <li> från PHP

  2. Varför anropar PostgreSQL min STABLE/IMMUTABLE-funktion flera gånger?

  3. MyIsam-motortransaktionsstöd

  4. PostgreSQL Connection Pooling:Del 1 – För- och nackdelar