sql >> Database >  >> RDS >> Oracle

Krijg accountgegevens in Oracle met behulp van functie

Je lijkt een beetje chaotisch te zijn in de probleembeschrijving, formatteer je vraag en maak hem leesbaarder. De oplossingen zijn in ieder geval simpel. Je hebt maar één if . nodig statement, waarbij je, afhankelijk van het niveau, zoekt in de eerste of tweede tabel en de juiste kolom:

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;

Hier zijn tabellen en voorbeeldfunctieaanroepen:

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

Gebruik de juiste kolomnamen die u in uw echte gegevens heeft, en pas indien nodig variabele typen en lengte aan. Ik denk dat je ook één samengevoegde query kunt gebruiken, geen speciale functie nodig, zoiets als hieronder. Ik gebruikte full join , omdat uw voorbeelden geen overeenkomende rijen bevatten. Waarschijnlijk eenvoudig join zal genoeg zijn.

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 )

Resultaat:

DIM_CUST_KEY
------------
        1123

Als je with . verwijdert en cross join delen en voeg into clausule dan kunt u deze query in functie gebruiken in plaats van if verklaring.

Bewerken:

Sorry voor de vertraging, ik heb de laatste tijd niet naar Stack Overflow gekeken. Hier zijn twee voorbeelden om uw functies te schrijven:

Deze functie retourneert een aaneengeschakelde tekenreeks:

select get_details_1('[112].[22].[1],[289].[20].[2],[301].[21].[3]') as list from dual;

LIST
------------------
1123,1576,1587

En de tweede functie is gepijplijnd en retourneert gegevens als vooraf gedefinieerde verzameling tekenreeksen, dus waarden staan ​​in afzonderlijke rijen.

select column_value 
  from table(get_details_2('[112].[22].[1],[289].[20].[2],[301].[21].[3]'));

COLUMN_VALUE
------------
        1123
        1576
        1587

U kunt ook eerst alle invoergegevens ontleden, ze in een verzameling opslaan en vervolgens bulkverzameling in één query gebruiken. Er zijn veel oplossingen en mogelijkheden, persoonlijk zou ik de pijplijnfunctie gebruiken, maar het hangt af van welke vorm van uitvoer je nodig hebt (verzameling of aaneengeschakelde string). U kunt ook begin ... end . toevoegen uitzondering blokkeren en afhandelen when no_data_found . U kunt dan speciale informatie presenteren of de uitvoering onderbreken, het hangt af van welk gedrag in een dergelijke situatie wordt verwacht.

Functie 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;

Functie 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;



  1. Kan tabel niet kopiëren naar een andere database met pg_dump

  2. InnoDB SELECT ... FOR UPDATE-instructie die alle rijen in een tabel vergrendelt

  3. Hoe rijen in een SQL Server-resultatenset te beperken

  4. Tel mysql union-type query