2009-12-14 11 views
0

J'essaie d'utiliser une fonction pipelined pour économiser à temps et réduire la redondance dans mes requêtes. La fonction en question renvoie des données d'une table de référence en fonction d'une entrée. Les enregistrements de la table de données principale que je sélectionne comportent plusieurs colonnes qui se réfèrent toutes à la table de référence. Le problème que je rencontre est que lorsque j'essaie d'utiliser la fonction pipelined plus d'une fois dans la requête, j'obtiens une erreur "cursor already open".PL/SQL - utilise deux fois la même fonction pipelined dans la même requête

Par exemple:

select xmlelement("genInf", xmlelement("ID", vt.ID), 
          xmlelement("vID", vt.V_ID), 
          xmlelement("vNum", vt.V_NUM), 
          xmlelement("terrDataCode", TERR_CODE.column_value), --data is based on reference table 
          xmlelement("ABValCode", AB_VAL_CD.column_value), --data is based on reference table 
          ... 
from V_TAB vt, table(UTIL.fn_getOvrdValXML(vt.terr_cd_id)) TERR_CODE, 
       table(UTIL.fn_getOvrdValXML(vt.ab_val_id)) AB_VAL_CD 
where vt.ID = in_vID; 

Cela a bien fonctionné jusqu'à ce que j'ajouté la deuxième référence à ma fonction de pipeline (fn_getOvrdValXML), et je reçois maintenant l'erreur « curseur est déjà ouvert ».

La fonction pipe-line est très simple:

type t_XMLTab is table of XMLType; --this type is in the spec 
.... 
function fn_getOvrdValXML(in_ID in ovrd.id%type) return t_XMLTab 
     pipelined is 
    begin 
     for r in C_OvrdVal(in_ID) loop 
      pipe row(r.XMLChunk); 
     end loop; 
     return; 
    end; 

Le curseur est de la même simple:

cursor C_OvrdVal(in_ID in ovrd.id%type) is 
     select xmlforest(ID as "valueID", S_VAL as "sValue", U_VAL as "uplValue", 
          O_VAL as "oValue", O_IND as "oIndicator", F_VAL as "finalValue", 
          O_RSN as "reason") AS XMLChunk 
     from ovrd_val xov; 
     where xov.id = in_ID; 

est-il un moyen de contourner ce problème, ou devrais-je essayer de résoudre ce problème (la problème de devoir référencer ovrd_val et sortir une xmlforest de la même manière beaucoup de beaucoup de fois) différemment?

Je dois admettre que je suis nouveau aux fonctions canalisées je ne suis pas 100% sûr que ce soit une utilisation appropriée, mais il était logique à l'époque et je suis ouvert à d'autres idées;)

+0

Il y a probablement une erreur dans la définition du curseur - ";" après xov – jva

+0

@jva: le curseur fonctionne correctement lorsqu'il est testé séparément. – FrustratedWithFormsDesigner

+0

@Frustrated: Ne valait pas la peine d'aborder le problème du curseur - vous obtenez la fonctionnalité que vous voulez sans les tracas. La seule optimisation supplémentaire serait si vous pouvez faire la vue dans une vue matérialisée, mais les restrictions sont très contraignantes. –

Répondre

1

Si vous « re en utilisant les fonctions de pipeline, alors vous êtes sur minimum 9i qui signifie que vous pouvez utiliser la clause WITH:

WITH ovrdValXML AS (
    select xov.id, 
     xmlforest(ID as "valueID", S_VAL as "sValue", U_VAL as "uplValue", 
         O_VAL as "oValue", O_IND as "oIndicator", F_VAL as "finalValue", 
         O_RSN as "reason") AS XMLChunk 
    from ovrd_val xov) 
SELECT xmlelement("genInf", xmlelement("ID", vt.ID), 
         xmlelement("vID", vt.V_ID), 
         xmlelement("vNum", vt.V_NUM), 
         xmlelement("terrDataCode", TERR_CODE.column_value), --data is based on reference table 
         xmlelement("ABValCode", AB_VAL_CD.column_value), --data is based on reference table 
         ... 
    FROM V_TAB vt 
    JOIN ovrdValXML terr_code ON terr_code = vt.? 
          AND terr_code.id = vt.terr_cd_id 
    JOIN ovrdValXML ab_val_cd ON ab_val_cd = vt.? 
          AND ab_val_cd.id = vt.ab_val_cd 
WHERE vt.id = IN_VID; 

Untested, et il est clair pas ce que vous vous joignez aussi - d'où le ? sur les critères de jointure.

+0

Hmm intéressant ... Cette requête n'est pas la seule qui aura besoin de la fonctionnalité d'ordValXML - il y en a plusieurs autres - environ 6 par mon dernier compte, et il y a une possibilité d'en ajouter d'autres. La raison pour laquelle j'ai initialement utilisé la fonction pipelined (je suis sur 10g) était que cela semblait être la solution la plus utilisable. Sauf que ça ne marche pas comme je le pensais. :( – FrustratedWithFormsDesigner

+2

@Frustrated: Une vue serait la solution la plus réutilisable - il suffit de déplacer le contenu encapsulé dans la clause WITH dans une vue –

+0

Pour les fonctions en pipeline, l'optimiseur doit deviner la cardinalité, etc. mauvais plan (surtout si vous avez plusieurs d'entre eux dans une requête) J'irais avec une vue, mais probablement une 'vraie' CREATE VIEW une plutôt qu'une vue en ligne ou avec un –

0

Avez-vous essayé de fermer réellement votre curseur à l'intérieur de cette fonction pipelinée avant de canaliser la ligne?

OPEN C_OvrdVal(in_ID); 
FETCH c_OrdVal INTO my_chunk_variable; 
CLOSE C_OrdVal; 
PIPE ROW my_chunk_variable; 
RETURN; 
+0

Je pensais que le curseur de la boucle était censé gérer cela automatiquement. – FrustratedWithFormsDesigner