Problème de trigger (BdD et trigger présents) - SQL/NoSQL - Programmation
Marsh Posté le 26-04-2004 à 17:37:13
Le problème des tables mutantes sous oracle est connu.
Ajouter un traitement des exceptions ne changera pas grand-chose.
Pas le temps d'expliquer cela maintenant en 3 lignes, alors je te conseille la lecture de cet article sur le sujet :
http://sgbd.developpez.com/oracle/ora-04091/
Marsh Posté le 27-04-2004 à 01:40:20
j'ai créé une table temporaire :
create global temporary table TEMP_COMMANDE
(
Prem_Comm VARCHAR2(1) null
)
/
insert into TEMP_COMMANDE values('N');
et créé un nouveau trigger qui remplace la fonction VerifAchat :
Create or Replace Trigger TrigUpdateTemp
before insert on LIGNE_COMMANDE
for each row
declare
nbachat NUMBER(3);
begin
select nvl(count(lc.NumCommande),0) into NbAchat from LIGNE_COMMANDE lc
where lc.NumCommande = :New.NumCommande;
if NbAchat <= 1 then
update TEMP_COMMANDE set Prem_Comm = 'O';
end if;
end;
/
puis modifié la partie du premier trigger pour renseigner la variable OK :
select *
into PremiereCommande
from TEMP_COMMANDE;
/*
A la suite de l'insertion d'une ligne dans la table LIGNE_COMMANDE, un premier
trigger s'est déclenché. Si l'insertion concernait la première commande alors
l'élément de la table TEMP_COMMANDE a pris pour valeur 'O', sinon il reste égal
à 'N'.
*/
if PremiereCommande = 'O' then
OK := 'O';
else
OK := 'N';
end if;
Je n'ai plus l'air d'avoir le problème de la table mutante
mais un autre problème est apparu :
insert into LIGNE_COMMANDE values(1,'VE189D',2,20.54)
*
ERREUR à la ligne 1 :
ORA-01403: Aucune donnée trouvée
ORA-06512: à "INTER.TRIGINSERCOMM", ligne 55
ORA-04088: erreur lors d'exécution du déclencheur 'INTER.TRIGINSERCOMM'
Je précise que ma table COMMANDE est bien renseignée
est ce au niveau de cette partie du trigger qu'il y a un problème :
if (HCodeCliPriv = 'N') then
select cp.CumAchatCarte
into HCumAchatPriv
from CARTE_PRIVILEGE cp, CLIENT cl, COMMANDE co
where co.NumCommande = :New.NumCommande
and co.NumClient = cl.NumClient
and cp.NumClient = cl.NumClient;
dbms_output.put_line('Cumul d''achat avec la carte = '||HCumAchatPriv);
end if;
Merci encore pour votre patience
Marsh Posté le 26-04-2004 à 17:11:34
Salut
j'ai l'erreur suivante lors de l'éxécution de mon trigger :
"
insert into LIGNE_COMMANDE values(1,'VE189D',2,20.54)
*
ERREUR à la ligne 1 :
ORA-04091: table INTER.LIGNE_COMMANDE en mutation, déclencheur/fonction ne peut la voir
ORA-06512: à "INTER.VERIFACHAT", ligne 11
ORA-06512: à "INTER.TRIGINSERCOMM", ligne 71
ORA-04088: erreur lors d'exécution du déclencheur 'INTER.TRIGINSERCOMM'
"
je ne vois pas d'où ça vient
je travaille sous Oracle 8i, et la base concerne une vente par correspondance de type Redoute.
voici mes tables :
-- ===================================================================
-- création de la séquence pour numéroter les cartes privilèges
-- ===================================================================
Create sequence SeqCarte
start with 26
increment by 1;
-- ======================================================
-- création de la séquence pour numéroter les commandes
-- ======================================================
Create sequence SeqComm
start with 1
increment by 1;
-- ============================================================
-- Table : PARAMETRE
-- ============================================================
create table PARAMETRE
(
DATEJOUR DATE null
)
/
-- =============================================================
-- Table : CLIENT
-- =============================================================
create table CLIENT
(
NUMCLIENT NUMBER(6) not null,
NOMCLIENT VARCHAR2(15) null ,
PRENOMCLIENT VARCHAR2(15) null ,
RUECLIENT VARCHAR2(30) null ,
CPCLIENT INTEGER null ,
VILLECLIENT VARCHAR2(25) null ,
TELCLIENT INTEGER null ,
CUMACHATCLIENT NUMBER(8,2) null ,
CODECLIENTPRIVILEGE VARCHAR2(1) null ,
constraint PK_CLIENT primary key (NUMCLIENT)
)
/
-- ============================================================
-- Table : TVA
-- ============================================================
create table TVA
(
CODETVA INTEGER not null,
TAUXTVA NUMBER(4,2) null ,
constraint PK_TVA primary key (CODETVA)
)
/
-- ============================================================
-- Table : FOURNISSEUR
-- ============================================================
create table FOURNISSEUR
(
CODEFOURNISSEUR NUMBER(3) not null,
NOMFOURNISSEUR VARCHAR2(35) null ,
ADRESSEFOURNISSEUR VARCHAR2(70) null ,
constraint PK_FOURNISSEUR primary key (CODEFOURNISSEUR)
)
/
-- ============================================================
-- Table : DATERAV
-- ============================================================
create table DATERAV
(
DATERAVITAILLEMENT DATE not null,
constraint PK_DATE primary key (DATERAVITAILLEMENT)
)
/
-- =======================================================================================
-- Table : COMMANDE
-- =======================================================================================
create table COMMANDE
(
NUMCOMMANDE NUMBER(6) not null,
NUMCLIENT NUMBER(6) not null,
DATECOMMANDE DATE null ,
constraint PK_COMMANDE primary key (NUMCOMMANDE) ,
constraint FK_COMMANDE_CLIENT foreign key (NUMCLIENT) references CLIENT (NUMCLIENT)
)
/
-- ====================================================================================
-- Table : TYPE_PRODUIT
-- ====================================================================================
create table TYPE_PRODUIT
(
CODETYPE VARCHAR2(5) not null,
CODETVA INTEGER not null,
LIBELTYPE VARCHAR2(35) null ,
MOISREDUCTYPE VARCHAR2(2) null ,
constraint PK_TYPE_PRODUIT primary key (CODETYPE) ,
constraint FK_TYPE_PRODUIT_TVA foreign key (CODETVA) references TVA (CODETVA)
)
/
-- ==============================================================================================================
-- Table : PRODUIT
-- ==============================================================================================================
create table PRODUIT
(
REFPRODUIT VARCHAR2(6) not null,
CODETYPE VARCHAR2(5) not null,
DESIGPRODUIT VARCHAR2(25) null ,
PU_HT_UNITPRODUIT NUMBER(6,2) null ,
QUANTITESTOCK INTEGER null ,
STOCKALERTE INTEGER null ,
DELAISFOURNISSEUR INTEGER null ,
constraint PK_PRODUIT primary key (REFPRODUIT) ,
constraint FK_PRODUIT_TYPE_PRODUIT foreign key (CODETYPE) references TYPE_PRODUIT (CODETYPE)
)
/
-- ==============================================================================================
-- Table : CARTE_PRIVILEGE
-- ==============================================================================================
create table CARTE_PRIVILEGE
(
NUMCARTE INTEGER not null,
NUMCLIENT INTEGER not null,
DATEDELIVRCARTE DATE null ,
CUMACHATCARTE NUMBER(8,2) null ,
constraint PK_CARTE_PRIVILEGE primary key (NUMCARTE) ,
constraint FK_CARTE_PRIVILEGE_CLIENT foreign key (NUMCLIENT) references CLIENT (NUMCLIENT)
)
/
-- ===================================================================================================
-- Table : LIGNE_COMMANDE
-- ===================================================================================================
create table LIGNE_COMMANDE
(
NUMCOMMANDE NUMBER(6) not null,
REFPRODUIT VARCHAR2(6) not null,
QUANTITECOMMANDEE NUMBER(4) null ,
PU_HTCOMMANDE NUMBER(8,2) null ,
constraint PK_LIGNE_COMMANDE primary key (NUMCOMMANDE, REFPRODUIT) ,
constraint FK_LC_COMM foreign key (NUMCOMMANDE) references COMMANDE (NUMCOMMANDE) ,
constraint FK_LC_PROD foreign key (REFPRODUIT) references PRODUIT (REFPRODUIT)
)
/
-- =======================================================================
-- Table : RAVITAILLER
-- =======================================================================
create table RAVITAILLER
(
REFPRODUIT VARCHAR2(6) not null,
CODEFOURNISSEUR NUMBER(3) not null,
DATERAVITAILLEMENT DATE not null,
QUANTITERAVITAILLEMENT VARCHAR2(10) null ,
constraint PK_RAVITAILLER primary key (REFPRODUIT, CODEFOURNISSEUR, DATERAVITAILLEMENT) ,
constraint FK_RAV_PROD foreign key (REFPRODUIT) references PRODUIT (REFPRODUIT) ,
constraint FK_RAV_FOUR foreign key (CODEFOURNISSEUR) references FOURNISSEUR (CODEFOURNISSEUR) ,
constraint FK_RAV_DATE foreign key (DATERAVITAILLEMENT) references DATERAV (DATERAVITAILLEMENT)
)
/
-- ============================================================
-- Renseignement Table : PARAMETRE
-- ============================================================
insert into PARAMETRE values(sysdate);
-- ============================================================
-- Renseignement Table : CLIENT
-- ============================================================
insert into CLIENT values(213546, 'Lepage', 'Arnaud', '3 Av. Lacassagne', 69003, 'Lyon', 0478598641, 50, 'N');
insert into CLIENT values(321654, 'Chanove', 'Laurent', '4 Rue de Garenne', 69005, 'Lyon', 0472235812, 148.23, 'N');
insert into CLIENT values(123456, 'Djanov', 'Popov', '122 Bd. du Kremlin', 75012, 'Paris', 0156751247, 3620.50, 'O');
-- ============================================================
-- Rensignement Table : TVA
-- ============================================================
insert into TVA values(1, 19.6);
insert into TVA values(2, 5.5);
-- ============================================================
-- Table : FOURNISSEUR
-- ============================================================
insert into FOURNISSEUR values(013, 'Fournitout', '111 Chemin du Coin 38230 Patelin');
insert into FOURNISSEUR values(001, 'FourOne', '1 Route de Jsepahou 69465 Kekpar');
insert into FOURNISSEUR values(066, 'RavitailPLus', '66 Route Soissentesi 42851 Houkeces');
-- ============================================================
-- Table : TYPE_PRODUIT
-- ============================================================
insert into TYPE_PRODUIT values(1, 1, 'bricolage', 4);
insert into TYPE_PRODUIT values(2, 2, 'culturel', 9);
insert into TYPE_PRODUIT values(3, 1, 'electroménager', 10);
insert into TYPE_PRODUIT values(4, 1, 'electronique', 9);
insert into TYPE_PRODUIT values(5, 1, 'jouet', 2);
insert into TYPE_PRODUIT values(6, 1, 'sport', 5);
insert into TYPE_PRODUIT values(7, 1, 'vêtement enfant', 1);
insert into TYPE_PRODUIT values(8, 1, 'vêtement femme', 1);
insert into TYPE_PRODUIT values(9, 1, 'vêtement homme', 1);
-- ============================================================
-- Table : PRODUIT
-- ============================================================
insert into PRODUIT values('SP512A', 6, 'Velo de route', 490.49, 13, 5, 0;
insert into PRODUIT values('SP258Z', 6, 'VTT', 390.00, 21, 5, 0;
insert into PRODUIT values('VE523B', 7, 'combinaison', 10.43, 45, 42, 0;
insert into PRODUIT values('VE189D', 7, 'jean 12ans', 20.54, 45, 40, 0;
insert into PRODUIT values('VF546G', 8, 'robe soirée noire', 125.54, 46, 45, 0;
insert into PRODUIT values('VF786L', 8, 'top en soie rouge', 20.92, 70, 65, 0;
insert into PRODUIT values('VH453H', 9, 'pantalon beige', 80.65, 87, 35, 0;
insert into PRODUIT values('VH789T', 9, 't-shirt colle V', 25.62, 56, 50, 0;
insert into PRODUIT values('JO450J', 5, 'train électrique', 120.36, 8, 5, 0;
insert into PRODUIT values('JO758S', 5, 'poupée cheveux blonds', 65.21, 53, 5, 0;
insert into PRODUIT values('JO471R', 5, 'Chalet en bois', 42.52, 45, 5, 0;
insert into PRODUIT values('EM486M', 3, 'lave-linge', 315.99, 13, 8, 0;
insert into PRODUIT values('EM786K', 3, 'réfrigérateur 288 L', 499.99, 15, 6, 0;
insert into PRODUIT values('EM546G', 3, 'Congélateur coffre 380 L', 419.59, 11, 6, 0;
insert into PRODUIT values('EM417N', 3, 'Sèche-cheveux 200W', 89.49, 7, 6, 0;
insert into PRODUIT values('BR481T', 1, 'perçeuse 300W', 215.49, 8, 7, 0;
insert into PRODUIT values('BR156A', 1, 'kit tournevis', 55.89, 22, 11, 0;
insert into PRODUIT values('BR151G', 1, 'établi 4m', 100.00, 24, 4, 0;
insert into PRODUIT values('EL432F', 4, 'micro-chaine 200W', 215.49, 15, 8, 0;
insert into PRODUIT values('EL121P', 4, 'platine disque vynil', 229.49, 32, 6, 0;
insert into PRODUIT values('EL482Y', 4, 'baladeur CD bleu', 69.54, 45, 15, 0;
insert into PRODUIT values('CD841G', 2, 'CD Cloclo', 9.12, 65, 26, 0;
insert into PRODUIT values('CD486H', 2, 'CD Best Of Jazz', 15.45, 45, 25, 0;
insert into PRODUIT values('CD158J', 2, 'CD Best Of Blues', 10.47, 42, 25, 0;
insert into PRODUIT values('CL458Z', 2, 'Livre ville de Lyon', 18.49, 27, 25, 0;
insert into PRODUIT values('CL7456', 2, 'Luvre cuisine pratique', 14.75, 48, 25, 0;
insert into PRODUIT values('DV154S', 2, 'DVD Imagina', 15.23, 54, 20, 0;
insert into PRODUIT values('DV841Q', 2, 'DVD Doc civ antiques', 15.23, 26, 20, 0;
-- ============================================================
-- Renseignement Table : CARTE_PRIVILEGE
-- ============================================================
insert into CARTE_PRIVILEGE values(SeqCarte.NextVal, 123456, '12/12/03', 18.49);
Et voici le trigger :
Create Or Replace Trigger TrigInserComm
after insert on LIGNE_COMMANDE
for each row
declare
HCumAchat NUMBER(8,2);
HNumeroCli NUMBER(6);
HCodeCliPriv VARCHAR2(1);
HDateComm DATE;
HMoisReduc VARCHAR2(2);
HQteStock INTEGER;
HRefProd VARCHAR2(6);
HTVA NUMBER(4,2);
OK VARCHAR2(1);
begin
dbms_output.put_line('Numero de commande = '||:New.NumCommande);
dbms_output.put_line('Reference du produit commandé = '||:New.RefProduit);
dbms_output.put_line('Quantite de produit commandee = '||:New.QuantiteCommandee);
dbms_output.put_line('Prix unitaire du produit commande = '||:New.PU_HTCommande);
select cl.CumAchatClient
into HCumAchat
from CLIENT cl, COMMANDE co
where :New.NumCommande = co.NumCommande
and co.NumClient = cl.NumClient;
dbms_output.put_line('Cumul d''achat = '||HCumAchat);
select cl.NumClient
into HNumeroCli
from CLIENT cl, COMMANDE co
where :New.NumCommande = co.NumCommande
and co.NumClient = cl.NumClient;
dbms_output.put_line('Numero du client = '||HNumeroCli);
select cl.CodeClientPrivilege
into HCodeCliPriv
from CLIENT cl, COMMANDE co
where :New.NumCommande = co.NumCommande
and co.NumClient = cl.NumClient;
dbms_output.put_line('Code Privilege = '||HCodeCliPriv);
select co.DateCommande
into HDateComm
from COMMANDE co
where co.NumCommande = :New.NumCommande;
dbms_output.put_line('Date de la commande = '||HDateComm);
select tp.MoisReducType
into HMoisReduc
from PRODUIT p, TYPE_PRODUIT tp
where p.RefProduit = :New.RefProduit
and p.CodeType = tp.CodeType;
dbms_output.put_line('Mois de réduction = '||HMoisReduc);
select p.QuantiteStock
into HQteStock
from PRODUIT p
where p.RefProduit = :New.RefProduit;
dbms_output.put_line('La quantite en stock du produit est = '||HQteStock);
select t.TauxTVA
into HTVA
from TVA t, TYPE_PRODUIT tp, PRODUIT p
where p.RefProduit = :New.RefProduit
and tp.CodeType = p.CodeType
and t.CodeTVA = tp.CodeTVA;
dbms_output.put_line('Le taux de TVA du produit en cour de commande est = '||HTVA);
/*
On éxécute d'abord la fonction VerifAchat avec le numéro de commande associé
à la commande en cours, si c'est le premier achat OK prend 'O' sinon 'N'.
*/
OK := VerifAchat(:new.NumCommande);
/*
Si c'est le premier achat et que le client n'a pas de carte privilège
(CodeClientPrivilege = 'N'), il peut en avoir une si son cumul d'achat est supérieur
à 300.
Ce test est fait au début de chaque insertion dans la table LIGNE_COMMANDE
car si l'insertion concerne la première commande, le client aura sa carte avant de
cumuler les achats.
Son code client privilege passe à 'O' et une carte privilege est crée avec son
numéro de client.
*/
if (OK = 'O') and (HCumAchat >= 300) and (HCodeCliPriv = 'N') then
update CLIENT set CodeClientPrivilege = 'O'
where NumClient = HNumeroCli;
insert into CARTE_PRIVILEGE values(SeqCarte.NextVal, HNumeroCli, SysDate, 0);
end if;
/*
Trois tests sont alors fait avant le cumul d'achat.
Si l'achat est réalisé par un client privilégié et que son cumul d'achat sur la carte
est supérieur à 500, alors celui-ci pourra bénéficier d'une remise de 10% sur l'achat
(une multiplication par 0.9 est réalisée, ce qui équivaut à soustraire au prix d'achat
le résultat de la multiplication du prix par la réduction).
Si en plus le produit acheté bénéficie d'une remise sur le mois d'achat, le client
aura une remise de 5%.
Si un client privilégié a son cumul d'achat sur la carte inférieur à 500, celui-ci est
considéré alors comme un client normal.
*/
if (HCodeCliPriv= 'O') then
if (to_char(HDateComm,'MM') = HMoisReduc) then
update CLIENT set CumAchatClient = HCumAchat + ((:new.PU_HTCOMMANDE*0.95)*(1+(HTVA/100)))
where NumClient = HNumeroCli;
else
update CLIENT set CumAchatClient = HCumAchat + (:new.PU_HTCOMMANDE*(1+(HTVA/100)))
where NumClient = HNumeroCli;
end if;
else
if (to_char(HDateComm,'MM') = HMoisReduc) then
update CLIENT set CumAchatClient = HCumAchat + ((:new.PU_HTCOMMANDE*0.95)*(1+(HTVA/100)))
where NumClient = HNumeroCli;
else
update CLIENT set CumAchatClient = HCumAchat + (:new.PU_HTCOMMANDE*(1+(HTVA/100)))
where NumClient = HNumeroCli;
end if;
end if;
/*
Suite à l'achat il faut supprimer la quantité de produit acheté à la quantité en stock du
produit concerné.
*/
update PRODUIT set QuantiteStock = HQteStock - :new.QuantiteCommandee
where RefProduit = :New.RefProduit;
end;
/
Faut-il une gestion des exceptions en rajoutant à la fin :
exception
when NO_DATA_FOUND
Dans ce cas que faudrait-il écrire après ?
Je désespère...
Merci d'avance pour vos réponses
@+
Rololo
arn.lepage@wanadoo.fr