CodeMaster
CodeMaster

Reputation: 449

Query to join Oracle tables

I have a 'MASTER' table as shown below:

Entity   Cat1         Cat2
A      Mary;Steve    Jacob
B      Alex;John     Sally;Andrew

Another table 'PERSON' has associations of person's name (this could be InfoID as well) with emails.

Name   Email               InfoID
Mary   [email protected]      mryD
Steve  [email protected]     stvR
Jacob  [email protected]     jacbb
Sally  [email protected]     sallD
Alex   [email protected]      alexT
John   [email protected]      johP
Andrew [email protected]    andV

I want to join the person table with master such as:

Entity  Cat1          EmailCat1                          Cat2              EmailCat2
A       Mary;Steve    [email protected];[email protected]   Jacob             [email protected]
B       Alex;John     [email protected];[email protected]    Sally;Andrew      [email protected];[email protected]

any insights on how to go about it?

Upvotes: 0

Views: 46

Answers (1)

Mahamoutou
Mahamoutou

Reputation: 1555

Honestly, your master table design needs to be normalized. But, in the meantime you could try this query below :

with 
  needed_rows_for_cat1_tab (lvl) as (
  select level from dual 
    connect by level <= (select max(regexp_count(Cat1, ';')) from Your_bad_master_tab) + 1
)
, needed_rows_for_cat2_tab (lvl) as (
  select level from dual 
    connect by level <= (select max(regexp_count(Cat2, ';')) from Your_bad_master_tab) + 1
)
, split_cat1_val_tab as (
      select Entity, Cat1
        , substr(Cat1||';'
          , lag(pos, 1, 0)over(partition by Entity order by lvl) + 1
          , pos - lag(pos, 1, 0)over(partition by Entity order by lvl) - 1
          ) val
        , lvl
        , pos
        , 1 cat
      from (
      select Entity, Cat1, instr(Cat1||';', ';', 1, r1.lvl)pos, r1.lvl
      from Your_bad_master_tab c1
        join needed_rows_for_cat1_tab r1 on r1.lvl <= regexp_count(Cat1, ';') + 1
      )
)
, split_cat2_val_tab as (
      select Entity, Cat2
        , substr(Cat2||';'
          , lag(pos, 1, 0)over(partition by Entity order by lvl) + 1
          , pos - lag(pos, 1, 0)over(partition by Entity order by lvl) - 1
          ) val
        , lvl
        , pos
        , 2 cat
      from (
      select Entity, Cat2, instr(Cat2||';', ';', 1, r2.lvl)pos, r2.lvl
      from Your_bad_master_tab c1
        join needed_rows_for_cat2_tab r2 on r2.lvl <= regexp_count(Cat2, ';') + 1
      )
)
select ENTITY
  , max(decode(cat, 1, CAT1, null)) CAT1
  , listagg(decode(cat, 1, EMAIL, null), ';')within group (order by lvl) EmailCat1 
  , max(decode(cat, 2, CAT1, null)) CAT2
  , listagg(decode(cat, 2, EMAIL, null), ';')within group (order by lvl) EmailCat2 
from (
  select c.*, p.Email
  from split_cat1_val_tab c join Your_person_tab p on (c.val = p.name)
  union all
  select c.*, p.Email
  from split_cat2_val_tab c join Your_person_tab p on (c.val = p.name)
)
group by ENTITY
;

Here are your sample data

--drop table Your_bad_master_tab purge;
create table Your_bad_master_tab (Entity, Cat1, Cat2) as
select 'A', 'Mary;Steve', 'Jacob' from dual union all
select 'B', 'Alex;John', 'Sally;Andrew' from dual
;

--drop table Your_person_tab purge;
create table Your_person_tab (Name, Email, InfoID) as               
select 'Mary',    '[email protected]'     ,'mryD'   from dual union all
select 'Steve',   '[email protected]'    ,'stvR'   from dual union all
select 'Jacob',   '[email protected]'    ,'jacbb'   from dual union all
select 'Sally',   '[email protected]'    ,'sallD'   from dual union all
select 'Alex',    '[email protected]'     ,'alexT'   from dual union all
select 'John',    '[email protected]'     ,'johP'   from dual union all
select 'Andrew',  '[email protected]'   ,'andV'   from dual
;

DB<>fiddle

Upvotes: 1

Related Questions