PL/SQL - Use a mesma função de pipeline duas vezes na mesma consulta
-
19-09-2019 - |
Pergunta
Estou tentando usar uma função de pipeline para economizar no tempo e reduzir a redundância em minhas consultas. A função em questão retorna dados de uma tabela de referência com base em alguma entrada. Registros na tabela de dados principais que estou selecionando, possuem várias colunas que se referem à tabela de referência. O problema que eu encontro é que, quando tento usar a função Pipelinizada mais de uma vez na consulta, recebo um erro de "cursor já aberto".
Por exemplo:
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;
Isso funcionou bem até que eu adicionei a segunda referência à minha função de pipeline (fn_getovrdValxml) e agora recebo o erro "cursor já aberto".
A função de pipeline é muito simples:
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;
O cursor é igualmente simples:
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;
Existe uma maneira de contornar isso ou devo tentar resolver esse problema (o problema de ter que fazer referência a OVRD_VAL e produzir um XMLForest da mesma maneira muitas muitas vezes) de maneira diferente?
Admito que sou novo nas funções de pipeline, então não tenho 100% de certeza de que este é um uso apropriado, mas fazia sentido no momento e estou aberto a outras idéias;)
Solução
Se você estiver usando funções de pipeline, você está no mínimo 9i, o que significa que você pode usar a cláusula com:
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;
Não testado, e não está claro o que você está se juntando também - daí o ?
nos critérios de junção.
Outras dicas
Você já tentou fechar seu cursor dentro dessa função de pipeline antes da linha de tubulação?
OPEN C_OvrdVal(in_ID);
FETCH c_OrdVal INTO my_chunk_variable;
CLOSE C_OrdVal;
PIPE ROW my_chunk_variable;
RETURN;