sql >> Databáze >  >> RDS >> Oracle

Použití IF EXISTS (SELECT ...) ve spouštěči BEFORE INSERT (Oracle)

Za prvé, pokud používáte SQL*Plus, když vytvoříte objekt a je vám řečeno, že došlo k chybám kompilace, příkaz show errors zobrazí chyby.

Pokud jste spustili show errors , bylo by vám řečeno, že IF EXISTS není platná syntaxe. Můžete udělat něco jako

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

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

Jakmile však chybu kompilace opravíte, skončíte s chybami za běhu. Ve spouštěči na úrovni řádku na surveillance , nelze obecně dotazovat surveillance (můžete, pokud vše, co děláte, je INSERT VALUES která zaručeně vloží pouze jeden řádek). Pokud tak učiníte, dostanete za běhu chybu spouštěče mutace.

Z hlediska datového modelu, když se ocitnete při navrhování tabulky, ve které platná data pro konkrétní řádek závisí na datech uložených v jiných řádcích téže tabulky, obecně jste porušili zásady normalizace a obecně vám lépe poslouží oprava základní datový model.

Pokud jste skutečně odhodláni zachovat datový model, raději bych vytvořil materializovaný pohled, který se obnoví při odevzdání, který obsahuje data pouze pro řádky, které porušují vaše kritéria. Na tento materializovaný pohled pak můžete umístit omezení, která způsobí chyby v okamžiku potvrzení, když jsou porušena vaše kritéria. To bude vyžadovat zhmotněné protokoly zobrazení na vašem stole.

Pokud opravdu chcete zachovat datový model a chcete prosadit logiku pomocí spouštěčů, budete potřebovat klasické řešení se třemi spouštěči (nebo složený spouštěč se třemi částmi, pokud používáte 11.2 nebo novější). Vytvořili byste balíček se sbírkou hodnot primárního klíče. Spouštěč příkazu before by inicializoval kolekci. Spouštěč na úrovni řádku by vložil primární klíče řádků, které byly vloženy a/nebo aktualizovány do této kolekce. A pak by spouštěč příkazu after iteroval tuto kolekci a implementoval jakékoli kontroly, které byste chtěli. To je však hodně pohyblivých kusů, a proto to obecně nedoporučuji.

Navíc, i když všechny tyto části zprovozníte, vaše logika vás neochrání v prostředí pro více uživatelů. Když do systému zasáhne více uživatelů současně, je zcela možné, že jeden uživatel vloží řádek, druhý uživatel vloží další řádek s překrývajícím se rozsahem a poté se každá relace potvrdí. V takovém případě obě sady spouštěčů povolí změnu, ale stále vám v tabulce zůstanou data, která porušují vaše požadavky. Materializované zobrazení, protože je vynuceno v okamžiku potvrzení, nikoli v okamžiku vložení, bude správně fungovat ve víceuživatelském prostředí. Pokud chcete, aby spouštěče fungovaly v prostředí pro více uživatelů, museli byste je dále zkomplikovat přidáním další logiky, která vynucuje serializaci, která by blokovala insert druhé relace. od spuštění do první relace buď potvrzené, nebo vrácené zpět. To zvyšuje složitost, snižuje škálovatelnost a v závislosti na tom, jak je implementováno, může být pro podporu noční můra.




  1. Přidání ADO.NET Entity Data Model ve VS 2017 a nic se nestane

  2. SQL QUERY Problém s uspořádáním výsledků

  3. Je třeba odeslat oznámení v dávce 1000

  4. DATEDIFF() vs DATEDIFF_BIG() v SQL Server:Jaký je rozdíl?