Zdá se, že jste v popisu problému trochu chaotický, naformátujte prosím svou otázku a udělejte ji čitelnější. Každopádně řešení jsou jednoduchá. Potřebujete pouze jeden if
příkaz, kde v závislosti na úrovni hledáte v první nebo druhé tabulce a příslušném sloupci:
create or replace function get_accountdetails (par_input in varchar2) return varchar2 is
v_aid varchar2(10);
v_db varchar2(10);
v_lvl varchar2(10);
v_ret varchar2(20) := '';
begin
v_aid := regexp_substr(par_input, '\d+', 1, 1);
v_db := regexp_substr(par_input, '\d+', 1, 2);
v_lvl := regexp_substr(par_input, '\d+', 1, 3);
if v_lvl = 1 then
select dim_cust_key
into v_ret
from dim_cust_acnt
where level1_account_id = v_aid and database_id = v_db;
elsif v_lvl = 2 then
select dim_cust_key
into v_ret
from dim_cust_dept
where level2_account_id = v_aid and database_id = v_db;
else
select dim_cust_key
into v_ret
from dim_cust_dept
where level3_account_id = v_aid and database_id = v_db;
end if;
return v_ret;
end;
Zde jsou tabulky a ukázková volání funkcí:
create table dim_cust_acnt (dim_cust_key, level1_account_id, database_id) as (
select 1123, 112, 22 from dual union all
select 1234, 113, 23 from dual );
create table dim_cust_dept (dim_cust_key, level2_account_id, level3_account_id, database_id) as (
select 1587, 245, 301, 21 from dual union all
select 1576, 289, 304, 20 from dual);
select get_accountdetails('[112].[22].[1]') from dual; -- result: 1123
select get_accountdetails('[289].[20].[2]') from dual; -- result: 1576
select get_accountdetails('[301].[21].[3]') from dual; -- result: 1587
Použijte prosím správné názvy sloupců, které máte ve svých reálných datech, a v případě potřeby upravte typy a délku proměnných. Myslím, že byste také mohli použít jeden spojený dotaz, není potřeba žádná speciální funkce, něco jako níže. Použil jsem full join
, protože vaše příklady neobsahují odpovídající řádky. Pravděpodobně jednoduché join
bude stačit.
with t(par_input) as (select '[112].[22].[1]' from dual)
select dim_cust_key
from dim_cust_acnt a
full join dim_cust_dept d using (dim_cust_key)
cross join t
where ( 1 = regexp_substr(par_input, '\d+', 1, 3)
and regexp_substr(par_input, '\d+', 1, 1) = level1_account_id
and regexp_substr(par_input, '\d+', 1, 2) = a.database_id )
or ( 2 = regexp_substr(par_input, '\d+', 1, 3)
and regexp_substr(par_input, '\d+', 1, 1) = level2_account_id
and regexp_substr(par_input, '\d+', 1, 2) = d.database_id )
or ( 3 = regexp_substr(par_input, '\d+', 1, 3)
and regexp_substr(par_input, '\d+', 1, 1) = level3_account_id
and regexp_substr(par_input, '\d+', 1, 2) = d.database_id )
Výsledek:
DIM_CUST_KEY
------------
1123
Pokud odeberete with
a cross join
části a přidejte into
klauzule pak můžete tento dotaz použít ve funkci místo if
prohlášení.
Upravit:
Omlouvám se za zpoždění, v poslední době jsem se na Stack Overflow nedíval. Zde jsou dva příklady, jak napsat své funkce:
Tato funkce vrací zřetězený řetězec:
select get_details_1('[112].[22].[1],[289].[20].[2],[301].[21].[3]') as list from dual;
LIST
------------------
1123,1576,1587
A druhá funkce je zřetězená a vrací data jako předdefinovaný soubor řetězců, takže hodnoty jsou v samostatných řádcích.
select column_value
from table(get_details_2('[112].[22].[1],[289].[20].[2],[301].[21].[3]'));
COLUMN_VALUE
------------
1123
1576
1587
Můžete také nejprve analyzovat všechna vstupní data, uložit je do nějaké kolekce a poté použít hromadné shromažďování v jednom dotazu. Řešení a možností je mnoho, osobně bych použil zřetězenou funkci, ale záleží na tom, jakou formu výstupu potřebujete (kolekce nebo zřetězený řetězec). Můžete také přidat begin ... end
blokovat a zpracovávat výjimku when no_data_found
. Poté můžete prezentovat speciální informace nebo přerušit provádění, záleží na tom, jaké chování se v takové situaci očekává.
Funkce 1:
create or replace function get_details_1 (par_input in varchar2) return varchar2 is
v_aid varchar2(10);
v_db varchar2(10);
v_lvl varchar2(10);
v_ret varchar2(20);
v_all varchar2(200) := '';
i_cnt int := 0;
begin
loop
v_aid := regexp_substr(par_input, '\d+', 1, i_cnt + 1);
v_db := regexp_substr(par_input, '\d+', 1, i_cnt + 2);
v_lvl := regexp_substr(par_input, '\d+', 1, i_cnt + 3);
i_cnt := i_cnt + 3;
exit when v_aid is null;
select dim_cust_key
into v_ret
from dim_cust_acnt a
full join dim_cust_dept d using (dim_cust_key)
where (v_lvl = 1 and level1_account_id = v_aid and a.database_id = v_db)
or (v_lvl = 2 and level2_account_id = v_aid and d.database_id = v_db)
or (v_lvl = 3 and level3_account_id = v_aid and d.database_id = v_db);
v_all := v_all||','||v_ret;
end loop;
return ltrim(v_all, ',');
end;
Funkce 2:
create or replace function get_details_2 (par_input in varchar2)
return sys.odcinumberlist pipelined is
v_aid varchar2(10);
v_db varchar2(10);
v_lvl varchar2(10);
v_ret varchar2(20);
i_cnt int := 0;
begin
loop
v_aid := regexp_substr(par_input, '\d+', 1, i_cnt + 1);
v_db := regexp_substr(par_input, '\d+', 1, i_cnt + 2);
v_lvl := regexp_substr(par_input, '\d+', 1, i_cnt + 3);
i_cnt := i_cnt + 3;
exit when v_aid is null;
select dim_cust_key
into v_ret
from dim_cust_acnt a
full join dim_cust_dept d using (dim_cust_key)
where (v_lvl = 1 and level1_account_id = v_aid and a.database_id = v_db)
or (v_lvl = 2 and level2_account_id = v_aid and d.database_id = v_db)
or (v_lvl = 3 and level3_account_id = v_aid and d.database_id = v_db);
pipe row (v_ret);
end loop;
return;
end;