Oracle
 sql >> Database >  >> RDS >> Oracle

Il conteggio (*) non funziona correttamente

Un paio di punti. In primo luogo, stai abusando del pragma della transazione autonoma. È pensato per transazioni separate di cui è necessario eseguire il commit o il rollback indipendentemente dalla transazione principale. Lo stai usando per eseguire il rollback della transazione principale e non ti impegni mai se non ci sono errori.

E quelle "conseguenze impreviste" di cui qualcuno ha parlato? Uno di questi è che il tuo conteggio restituisce sempre 0. Quindi rimuovi il pragma sia perché viene utilizzato in modo improprio e quindi il conteggio restituirà un valore corretto.

Un'altra cosa è non avere commit o rollback all'interno dei trigger. Genera un errore e lascia che il codice di controllo faccia ciò che deve fare. So che i rollback erano dovuti al pragma. Non dimenticare di rimuoverli quando rimuovi il pragma.

Il seguente trigger funziona per me:

CREATE OR REPLACE TRIGGER trg_mytable_biu 
BEFORE INSERT OR UPDATE ON mytable 
FOR EACH ROW 
WHEN (NEW.TYPEB = 'Bert') -- Don't even execute unless this is Bert
DECLARE
    L_COUNT NUMBER;
BEGIN
    SELECT  COUNT(*) INTO L_COUNT
    FROM    MYTABLE 
    WHERE   ARTICLE = :NEW.ARTICLE
        AND TYPEB = :NEW.TYPEB;

    IF L_COUNT > 0  THEN
        RAISE_APPLICATION_ERROR( -20001, 'Bert already exists!' );
    ELSIF :NEW.STOCK_COUNT > 1 THEN
        RAISE_APPLICATION_ERROR( -20001, 'Can''t insert more than one Bert!' );
    END IF;
END;

Tuttavia, non è una buona idea che un trigger su una tabella acceda separatamente a quella tabella. Di solito il sistema non lo consente nemmeno:questo trigger non verrà eseguito affatto se modificato in "dopo". Se è consentito eseguire, non si può mai essere sicuri dei risultati ottenuti, come hai già scoperto. In realtà, sono un po' sorpreso che il trigger sopra funzioni. Mi sentirei a disagio ad usarlo in un database reale.

L'opzione migliore quando un trigger deve accedere alla tabella di destinazione è nascondere la tabella dietro una vista e scrivere un trigger "invece di" sulla vista. Quello trigger può accedere alla tabella quanto vuole.