PL/SQL – используйте одну и ту же конвейерную функцию дважды в одном запросе
-
19-09-2019 - |
Вопрос
Я пытаюсь использовать конвейерную функцию, чтобы сэкономить время и уменьшить избыточность в моих запросах.Рассматриваемая функция возвращает данные из справочной таблицы на основе некоторых входных данных.Записи в основной таблице данных, из которой я выбираю, имеют несколько столбцов, все из которых относятся к справочной таблице.Проблема, с которой я сталкиваюсь, заключается в том, что когда я пытаюсь использовать конвейерную функцию более одного раза в запросе, я получаю ошибку «курсор уже открыт».
Например:
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;
Это работало нормально, пока я не добавил вторую ссылку в свою функцию конвейера (fn_getOvrdValXML), и теперь я получаю ошибку «курсор уже открыт».
Конвейерная функция очень проста:
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;
Курсор аналогичен простому:
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;
Есть ли способ обойти это, или мне следует попытаться решить эту проблему (проблему необходимости ссылаться на ovrd_val и выводить xmlforest одним и тем же способом много-много-много раз) по-другому?
Признаюсь, я новичок в конвейерных функциях, поэтому не уверен на 100%, что это подходящее использование, но в то время это имело смысл, и я открыт для других идей;)
Решение
Если вы используете конвейерные функции, то у вас минимум 9i, что означает, что вы можете использовать предложение 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;
Непроверено, и тоже непонятно, к чему вы присоединяетесь - отсюда и ?
по критериям присоединения.
Другие советы
Пробовали ли вы закрыть курсор внутри этой конвейерной функции перед передачей строки?
OPEN C_OvrdVal(in_ID);
FETCH c_OrdVal INTO my_chunk_variable;
CLOSE C_OrdVal;
PIPE ROW my_chunk_variable;
RETURN;