Ако приемем вашия formData
структурата на таблицата е фиксирана и известна, можете просто да използвате израз за регистър, за да преведете formOption.fName
към съответстващата стойност на колона:
select fo.fieldLabel as label,
case fo.fieldName
when 'fName' then fd.fName
when 'lName' then fd.lName
when 'nName' then fd.mName
end as value
from formData fd
join fieldOptions fo
on fo.formType = fd.formtype
where fd.id = 3;
LABEL VALUE
-------------------- --------------------
First Frank
Surname Peterson
Middle Initial
...
where fd.id = 3;
LABEL VALUE
-------------------- --------------------
First Name Bob
Last Name Smith
Middle
След това можете да накарате вашата процедура да отвори референтен курсор за тази заявка, като използвате стойност на аргумент за стойността на ID.
Ако formData
структурата не е известна или не е статична, тогава вероятно имате по-големи проблеми; но за това ще трябва да се върнете към динамичен SQL. Като отправна точка можете да направите нещо като:
create procedure p42 (p_id number, p_refcursor out sys_refcursor) as
l_stmt varchar2(32767);
begin
l_stmt := 'select fo.fieldLabel as label, case lower(fo.fieldName) ';
for r in (
select column_name from user_tab_columns
where table_name = 'FORMDATA'
and data_type = 'VARCHAR2'
)
loop
l_stmt := l_stmt || ' when ''' || lower(r.column_name) || ''' then fd.' || r.column_name;
end loop;
l_stmt := l_stmt || ' end as value '
|| 'from formData fd '
|| 'join fieldOptions fo '
|| 'on fo.formType = fd.formtype '
|| 'where fd.id = :d1';
open p_refcursor for l_stmt using p_id;
end p42;
/
Това използва всички действително дефинирани колони в таблицата, за да създаде израза case по време на изпълнение; защото регистърът на вашите fieldName
може да не съвпада с речника на данните, принуждавам всичко да бъде с малки букви за сравнение. Също така се ограничавам до колони с низове, за да опростя случая, но ако имате нужда от колони, които са други типове данни, тогава всяка when ... then
клаузата на case изразите ще трябва да проверят типа данни на тази колона (който можете да добавите към r
курсор) и преобразувайте действителната стойност на колоната в низ по подходящ начин. Всички стойности трябва да завършват с един и същ тип данни, така че наистина трябва да са низове.
Както и да е, тествам това от SQL*Plus:
var rc refcursor
exec p42(1, :rc);
PL/SQL procedure successfully completed.
print rc
LABEL VALUE
-------------------- --------------------
First Name Bob
Last Name Smith
Middle
3 rows selected.
Можете да направите заявка fieldOptions
за да получите вместо това възможните имена на колони, но все пак може да имате проблем с преобразуването на типа данни, с който ще бъде по-трудно да се справите; но ако всички посочени formData
полетата всъщност са низове, тогава това би било:
for r in (
select fo.fieldName
from formData fd
join fieldOptions fo
on fo.formType = fd.formtype
where fd.id = p_id
)
loop
l_stmt := l_stmt || ' when ''' || r.fieldName || ''' then fd.' || r.fieldName;
end loop;