Oracle
 sql >> Base de données >  >> RDS >> Oracle

Count(*) ne fonctionne pas correctement

Quelques points. Tout d'abord, vous abusez du pragma de transaction autonome. Il est destiné aux transactions distinctes que vous devez valider ou annuler indépendamment de la transaction principale. Vous l'utilisez pour annuler la transaction principale - et vous ne validez jamais s'il n'y a pas d'erreur.

Et ces "conséquences imprévues" dont quelqu'un a parlé ? L'un d'eux est que votre décompte renvoie toujours 0. Supprimez donc le pragma à la fois parce qu'il est mal utilisé et que le décompte renverra une valeur appropriée.

Une autre chose est de ne pas avoir de commits ou d'annulations dans les déclencheurs. Générez une erreur et laissez le code de contrôle faire ce qu'il doit faire. Je sais que les retours en arrière étaient dus au pragma. N'oubliez pas de les supprimer lorsque vous supprimez le pragma.

Le déclencheur suivant fonctionne pour moi :

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;

Cependant, ce n'est pas une bonne idée qu'un déclencheur sur une table accède séparément à cette table. Habituellement, le système ne l'autorise même pas - ce déclencheur ne s'exécutera pas du tout s'il est remplacé par "après". S'il est autorisé à s'exécuter, on ne peut jamais être sûr des résultats obtenus - comme vous l'avez déjà découvert. En fait, je suis un peu surpris que le déclencheur ci-dessus fonctionne. Je me sentirais mal à l'aise de l'utiliser dans une vraie base de données.

La meilleure option lorsqu'un déclencheur doit accéder à la table cible consiste à masquer la table derrière une vue et à écrire un déclencheur "au lieu de" sur la vue. Ça le déclencheur peut accéder à la table autant qu'il veut.