| 2 kyra, le 6 aoû 2008 à 17:38:42Bonjour et merci de vous préoccuper de mon problème.
Mes deniers tests : avec 'execute immediate' Select avec variables & Select avec constantes... pas mieux
Le problème est sur 'val_pmp' qui est recherché au début du code; au départ, je le testais 'IF val_pmp > 0' avant de continuer et il ne se passait jamais rien puisqu'aucune valeur n'est renvoyée.
Le select ... from dual renvoie la valeur 0.221 sous SQL
Voici mon code :
CREATE OR REPLACE TRIGGER ETHIC.GRESSET_STOCKMATIERES_FR_PMP
AFTER INSERT or UPDATE or DELETE ON ETHIC.MVTSPHYSSTOCKMATIERES FOR EACH ROW
WHEN (NEW.TYPEMVT='ER') -- Si mvt de type Réception Automatique d'une Commande Fournisseur => 'ER'
Declare
val_pmp NUMBER;
fr_pmp NUMBER := 41023; --Id du fournisseur "PMP"
fr_pmp_existe NUMBER;
unite_prix_achat VARCHAR2(3) := '';
---------------------------------------------------------------------------------------------
-- AJ 2008-07-29 : A chaque réception de commande d'achat (Mvt Physique de matière de type 'ER')
-- Création / màj d'une ligne dans le fichier des fournisseurs de l'article,
-- avec prix = PMP (calculé dans l'unité d'achat de l'article)
BEGIN
execute immediate 'SELECT ETHIC.PKG1.PMP(''GGR'',3021) INTO val_pmp FROM Dual';
-- execute immediate 'SELECT ETHIC.PKG1.PMP(:NEW.CODESOCIETE,:NEW.IDREFSTOCK) INTO val_pmp FROM Dual';
-- val_pmp := ETHIC.PKG1.PMP(:NEW.CODESOCIETE,:NEW.IDREFSTOCK);
-- Recherche de l'unité du PMP = unité d'achat de la fiche article
Select CODEUNITEPRIXACHAT INTO unite_prix_achat FROM ETHIC.PSTOCKMATIERESENTETE where CODESOCIETE=:NEW.CODESOCIETE and IDREFSTOCK=:NEW.IDREFSTOCK;
-- SUPPRESSION du fournisseur 'PMP' si existe déjà pour cet article
BEGIN
DELETE FROM ETHIC.PSTOCKMATIERESFOURNISSEURS WHERE CODESOCIETE=:NEW.CODESOCIETE and IDREFSTOCK=:NEW.IDREFSTOCK and NOCOMPTE= fr_pmp;
EXCEPTION
WHEN OTHERS THEN NULL;
END;
-- [RE]CREATION de la ligne fournisseur "PMP"
BEGIN
Insert into ETHIC.PSTOCKMATIERESFOURNISSEURS values(:NEW.CODESOCIETE, 'GRE', :NEW.IDREFSTOCK, :NEW.CODECLASSE, 0, 0, 'F', fr_pmp, 'pmp', 0,nvl(val_pmp,888), unite_prix_achat, 'Valeur du PMP au ' || to_char(sysdate,'dd/mm/yyyy')) ;
EXCEPTION
WHEN OTHERS THEN NULL;
END;
EXCEPTION
WHEN OTHERS THEN NULL;
END; Répondre à kyra | OK... Il me semble que si tu vx retourner des données via la SP, tu ne peux pas le faire directement...
Il existerait deux solutions:
1. au lieu de passer par la SP, tu fais ton SELECT directement dans le trigger
2. si tu veux conserver ta SP, il faudra la modifier pour qu'elle possède un paramètre OUT de type sys_refcursor. Plsu d'infos sur le maniement des sys_refcursor dans les SP ici: http://www.digcode.com/...
++ Répondre à sandul | 8 kyra, le 7 aoû 2008 à 00:23:111. au lieu de passer par la SP, tu fais ton SELECT directement dans le trigger
Je crois que j'avais mal compris ta 1° proposition... tu me disais de remplacer l'appel de la fonction PMP par un select dans mon trigger : il ne s'agit pas d'un simple select mais d'un calcul complexe comportant de nombreux cas et appels d'autres fonctions... voilà pourquoi il faut que je passe par là : même si je voulais recopier le code de cette fonction directement dans le trigger, il y aurait d'autres appels de fonctions et si ça ne fonctionne pas dans un trigger, je suis mal-mal.
De plus, cette fonction m'a été livrée par le fournisseur de notre ERP.
... donc penses-tu que si l'appel de ma fonction PMP ne renvoie pas de résultat lorsqu'elle est appelée dans le trigger, le fait de rajouter un intermédiaire sous forme d'une procédure fonctionnera mieux ??? (c'est de cela que je doute)
Mais j'essaierai demain, et tout d'abord avec une fonction simplifiée... Répondre à kyra |
|
| Exemple:
CREATE TABLE a (b INT, c VARCHAR2(10));
CREATE TABLE b (ID INT, country VARCHAR2(10));
CREATE OR REPLACE PROCEDURE getcountry (iid IN INT, resultset OUT sys_refcursor)
AS
BEGIN
OPEN resultset FOR
SELECT country
FROM b
WHERE ID = iid;
END getcountry;
insert into b values (1, 'france');
insert into b values (2, 'usa');
commit;
CREATE OR REPLACE TRIGGER dispnew.a_trg
AFTER INSERT OR UPDATE OR DELETE
ON dispnew.a
FOR EACH ROW
WHEN (NEW.c = 'ER')
DECLARE
val_pmp VARCHAR2 (10);
val_pmp_rc sys_refcursor;
val_pmp_country a.c%TYPE;
---------------------------------------------------------------------------------------------
-- AJ 2008-07-29 : A chaque réception de commande d'achat (Mvt Physique de matière de type 'ER')
-- Création / màj d'une ligne dans le fichier des fournisseurs de l'article,
-- avec prix = PMP (calculé dans l'unité d'achat de l'article)
BEGIN
getcountry (1, val_pmp_rc);
LOOP
FETCH val_pmp_rc
INTO val_pmp_country;
EXIT WHEN val_pmp_rc%NOTFOUND;
DBMS_OUTPUT.put_line ('val_pmp=' || val_pmp_country);
END LOOP;
CLOSE val_pmp_rc;
EXCEPTION
WHEN OTHERS
THEN
NULL;
END;
insert into a (b, c) values (2, 'ER');
==> output sous Toad = val_pmp=france
Bon, il est vrai que je me suis égaré de ton code en simplifiant la procédure, mais tu as là qqch qui marche: trigger avec appel de SP. Répondre à sandul | 5 kyra, le 6 aoû 2008 à 19:36:05J'ai eu un peu de mal à saisir ce qu'était une SP au départ; puis j'ai essayé une variante de ce que vous proposez; mais ça ne marche pas mieux.
Promis : demain je fais une SP qui appelera ma fonction (mais j'ai quand même des doutes)
Question subsidiaire : DBMS_OUTPUT.put_line s'affiche où ? J'ai beau mettre SET SERVEROUTPUT ON ou dbms_output.enable(buffer_size => NULL); il ne se passe rien...
CREATE OR REPLACE TRIGGER ETHIC.GRESSET_STOCKMATIERES_FR_PMP
AFTER INSERT or UPDATE or DELETE ON ETHIC.MVTSPHYSSTOCKMATIERES FOR EACH ROW
WHEN (NEW.TYPEMVT='ER') -- Si mvt de type Réception Automatique d'une Commande Fournisseur => 'ER'
Declare
val_pmp NUMBER;
fr_pmp NUMBER := 41023; --Id du fournisseur "PMP"
unite_prix_achat VARCHAR2(3) := '';
val_pmp_rc sys_refcursor;
---------------------------------------------------------------------------------------------
-- AJ 2008-07-29 : A chaque réception de commande d'achat (Mvt Physique de matière de type 'ER')
-- Création / màj d'une ligne dans le fichier des fournisseurs de l'article,
-- avec prix = PMP (calculé dans l'unité d'achat de l'article)
BEGIN
BEGIN
OPEN val_pmp_rc FOR
SELECT ETHIC.PKG1.PMP(:NEW.CODESOCIETE,:NEW.IDREFSTOCK) FROM Dual;
END;
LOOP
FETCH val_pmp_rc INTO val_pmp;
EXIT WHEN val_pmp_rc%NOTFOUND;
DBMS_OUTPUT.put_line ('val_pmp=' || val_pmp);
END LOOP;
Insert into ETHIC.w_PSTOCKMATIERESFOURNISSEURS values(:NEW.CODESOCIETE, 'GRE', :NEW.IDREFSTOCK, :NEW.CODECLASSE, 0, 0, 'F', fr_pmp,
'pmp', 0,val_pmp, unite_prix_achat, 'Valeur du PMP au ' || to_char(sysdate,'dd/mm/yyyy')) ;
END; Répondre à kyra | demain je fais une SP qui appelera ma fonction <== je crois su'il est possible de retourner le sys_refcursor par une fonction, cf. la 2ème page du lien:
CREATE OR REPLACE FUNCTION get_emp_by_dept (i_deptno emp.deptno%TYPE)
RETURN SYS_REFCURSOR
IS
emp_refcur SYS_REFCURSOR;
BEGIN
OPEN emp_refcur FOR SELECT empno, ename FROM emp WHERE deptno = i_deptno;
RETURN emp_refcur;
END;
The following PL/SQL statement is used to harness the above Oracle function
DECLARE
deptno emp.deptno%TYPE;
empno emp.empno%TYPE;
ename emp.ename%TYPE;
emp_refcur SYS_REFCURSOR;
BEGIN
emp_refcur := get_emp_by_dept(deptno);
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME');
DBMS_OUTPUT.PUT_LINE('----- -------');
LOOP
FETCH emp_refcur INTO empno, ename;
EXIT WHEN emp_refcur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(empno || ' ' || ename);
END LOOP;
CLOSE emp_refcur;
END;
Du coup, si tu as fait ta modif dans la fonction (n'oublie pas de rajouter le return du curseur), il faudra changer cette ligne:
SELECT ETHIC.PKG1.PMP(:NEW.CODESOCIETE,:NEW.IDREFSTOCK) FROM Dual;
en:
val_pmp_rc := ETHIC.PKG1.PMP(:NEW.CODESOCIETE,:NEW.IDREFSTOCK) FROM Dual;
...
DBMS_OUTPUT.put_line s'affiche où ? J'ai beau mettre SET SERVEROUTPUT ON ==> probablement il ne passe pas par là... Enfin, sous Toad je vois l'output dans un onglet après avoir fait un enable de l'output qui correspond en gros à un SET SERVEROUTPUT ON
++ Répondre à sandul |
| Oups, erreur:
Pas de "FROM Dual" dans l'appel de la fonction ;-)
Malheureux copier-coller, damn... Répondre à sandul |
|
|
|