Du ser ud til at være lidt kaotisk i problembeskrivelsen, formater venligst dit spørgsmål og gør det mere læsbart. Løsningerne er i hvert fald enkle. Du behøver kun én if
sætning, hvor du afhængigt af niveau søger i første eller anden tabel og korrekt kolonne:
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;
Her er tabeller og eksempler på funktionskald:
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
Brug venligst de rigtige kolonnenavne, som du har i dine rigtige data, og juster variabeltyper og længde, hvis det er nødvendigt. Jeg tror, du også kunne bruge en samlet forespørgsel, ingen speciel funktion nødvendig, noget som nedenfor. Jeg brugte full join
, fordi dine eksempler ikke indeholder matchende rækker. Sandsynligvis simpel join
vil være nok.
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 )
Resultat:
DIM_CUST_KEY
------------
1123
Hvis du fjerner with
og cross join
dele og tilføje into
klausul, så kan du bruge denne forespørgsel i funktion i stedet for if
erklæring.
Rediger:
Beklager forsinkelsen, jeg så ikke på Stack Overflow for nylig. Her er to eksempler på, hvordan du skriver dine funktioner:
Denne funktion returnerer sammenkædet streng:
select get_details_1('[112].[22].[1],[289].[20].[2],[301].[21].[3]') as list from dual;
LIST
------------------
1123,1576,1587
Og den anden funktion er pipelinet og returnerer data som foruddefineret samling af strenge, så værdierne er i separate rækker.
select column_value
from table(get_details_2('[112].[22].[1],[289].[20].[2],[301].[21].[3]'));
COLUMN_VALUE
------------
1123
1576
1587
Du kan også parse alle inputdata først, gemme dem i en eller anden samling og derefter bruge bulk collect i én forespørgsel. Der er mange løsninger og muligheder, personligt ville jeg bruge pipelined funktion, men det kommer an på hvilken form for output du har brug for (samling eller sammenkædet streng). Du kan også tilføje begin ... end
blokere og håndtere undtagelse when no_data_found
. Du kan præsentere speciel info derefter eller bryde eksekveringen, det afhænger af hvilken adfærd der forventes i en sådan situation.
Funktion 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;
Funktion 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;