Précédent   Forum des professionnels en informatique > Bases de données > Oracle > PL/SQL
PL/SQL Forum d'entraide sur le PL/SQL
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 12/09/2007, 12h42   #1
Invité régulier
 
Inscription : septembre 2007
Messages : 3
Détails du profil
Informations forums :
Inscription : septembre 2007
Messages : 3
Points : 7
Points : 7
Par défaut Integrité referentiel appliqué par un trigger, recuperation des rejets associés

Nous tentons d'appliquer une integrité referentiel entre deux tables (CNT et CNU).
un enregistrement CNU(contrat unitaire) peut etre inserer si l'on trouve son contrat (CNT).
pour cela, nous utilisons un trigger.
il est declarer de la sorte et appliquer sur la table cible (CNU):

CREATE OR REPLACE TRIGGER CNU_CONTROLE_CNT
BEFORE INSERT ON CNU_CONTRAT_UNITAIRE
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
DECLARE
trouver NUMBER:=0 ;

BEGIN
-- vérifivation de la présence du contrat actif

SELECT COUNT(*) INTO trouver
FROM CNT_CONTRAT a
WHERE :new.CNT_CODE = a.CNT_CODE
AND :new.CNU_INV_DEB >= a.CNT_INV_DEB
and :new.CNU_INV_DEB < a.CNT_INV_FIN
;
IF trouver <> 0 THEN
RAISE_APPLICATION_ERROR(-00001,'NAME: Pas de contrat valide dans la table CNT_CONTRAT //END');
END IF;

END CNU_CONTROLE_CNT;
/


Nous nous attendons donc a recuperer les enregistrement rejetés par le trigger (on attend un fonctionnement identique a un rejet sur une PK/FK).
Cependant, le programme effectuant les insert passe en Failed dès qu'on 'tombe' sur un enregistrement ne respectant pas le trigger.
le message d'erreur envoyé est le suivant:

Severity Timestamp Node Thread Message Code Message
ERROR 11/09/2007 17:31:07 node01_rs39 WRITER_1_*_1 WRT_8229 Database errors occurred:
ORA-20011: NAME: Pas de contrat valide dans la table CNT_CONTRAT //END
ORA-06512: à "XOB.CNU_CONTROLE_CNT", ligne 14
ORA-04088: erreur lors d'exécution du déclencheur 'XOB.CNU_CONTROLE_CNT'

Comment peut on contourner le 'Failed' et recuperer les rejets associés au trigger?
prouveur.georges est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 12/09/2007, 13h22   #2
Expert Confirmé Sénior


 
Avatar de laurentschneider
 
Homme Laurent Schneider
Administrateur de base de données
Inscription : décembre 2005
Messages : 2 927
Détails du profil
Informations personnelles :
Nom : Homme Laurent Schneider
Localisation : Suisse

Informations professionnelles :
Activité : Administrateur de base de données
Secteur : Finance

Informations forums :
Inscription : décembre 2005
Messages : 2 927
Points : 4 549
Points : 4 549
pourquoi réinventé la roue?

Oracle a des contraintes d'inégrités référentielles bien plus efficaces qu'un trigger maison.

Quant à récupérer les enregistrements rejettés, il suffit de faire

Code :
INSERT INTO t VALUES (blabla) log errors ;
Merci de toujours préciser ta version
__________________
Mon blog : laurentschneider.com
Mon livre : Advanced Oracle SQL Programming
laurentschneider est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 12/09/2007, 13h56   #3
Invité régulier
 
Inscription : septembre 2007
Messages : 3
Détails du profil
Informations forums :
Inscription : septembre 2007
Messages : 3
Points : 7
Points : 7
Il est vrai qu'il est inutile de reinventer la roue!
le souci qui se pose est que l'on utilise un ETL, Informatica Powercenter pour charger dans les tables nos enregistrements.
Ainsi, quand oracle rejete un enregistrement pour contrainte d'integrité ou autre, nous avons le moyen de les recuperer.
Nous souhaitons alors appliquer une nouvelle contrainte referentiel (lié a une table 'mère'->un CNU ne peut etre inserer si le CNT n'existe pas).
L'idée est alors de laisser oracle géré le rejet lié a cette contrainte.
nous pensions qu'il rejeterait l'enregistrement 'normalement' (comme il peut le fait sur une contrainte d'integrité).

l'usage du trigger nous semble plus 'confortable' car ce type de contrainte d'integrité est a appliquer sur d'autres tables (suivant le meme principe: une table mère/une table fille, on insert dans la fille uniquement si on trouve la clé dans la mere).

Comment peut on lever un warning dans un trigger?
ce pourrait etre la solution... dans notre trigger on leve un erreur qui fait 'planter' l'application RAISE_APPLICATION_ERROR.
Si on utilise un 'raise_warning' l'application continuerait probablement son travail...

la version d'oracle utilisé est la 10g
prouveur.georges est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 12/09/2007, 14h38   #4
Expert Confirmé Sénior


 
Avatar de laurentschneider
 
Homme Laurent Schneider
Administrateur de base de données
Inscription : décembre 2005
Messages : 2 927
Détails du profil
Informations personnelles :
Nom : Homme Laurent Schneider
Localisation : Suisse

Informations professionnelles :
Activité : Administrateur de base de données
Secteur : Finance

Informations forums :
Inscription : décembre 2005
Messages : 2 927
Points : 4 549
Points : 4 549
je n'aime pas trop les triggers, c'est moins fiable que les contraintes.
__________________
Mon blog : laurentschneider.com
Mon livre : Advanced Oracle SQL Programming
laurentschneider est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 13/09/2007, 18h00   #5
Invité régulier
 
Inscription : septembre 2007
Messages : 3
Détails du profil
Informations forums :
Inscription : septembre 2007
Messages : 3
Points : 7
Points : 7
Par défaut [RESOLU]

Exact, les contraintes c'est meilleur!!!
la ruse est de modifier l'enregistrement a inserer pour qu'il soit rejeté par une contrainte existante(on ne peut pas ajouter de contrainte sur les tables).
Ainsi, nous avons un champ (que l'on renseigne toujours) qui doit etre non null.
nous nous servons de cette contrainte pour effectuer notre rejet dans notre trigger.
il suffit de mettre a null le champ lorque l'on tente d'inserer un enregistrement n'ayant pas de contrat CNU.

voici le code

CREATE OR REPLACE TRIGGER CNU_CONTROLE_CNT
BEFORE INSERT ON CNU_CONTRAT_UNITAIRE
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
DECLARE
trouver NUMBER:=0 ;

BEGIN
-- vérifivation de la présence du contrat actif

SELECT COUNT(*) INTO trouver
FROM CNT_CONTRAT a
WHERE :new.CNT_CODE = a.CNT_CODE
AND :new.CNU_INV_DEB >= a.CNT_INV_DEB
and :new.CNU_INV_DEB < a.CNT_INV_FIN
;
IF trouver=0 THEN
:new.CNU_INV_FIN := NULL;
END IF;

END CNU_CONTROLE_CNT;
/


Merci pour ton aide...ca m'a mis sur la bonne piste!
prouveur.georges est déconnecté   Envoyer un message privé Réponse avec citation 10
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 05h15.


 
 
 
 
Partenaires

Hébergement Web