0

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   maryD@gmail.com      mryD
Steve  steveR@gmail.com     stvR
Jacob  jacobB@gmail.com     jacbb
Sally  sallyD@gmail.com     sallD
Alex   AlexT@gmail.com      alexT
John   JohnP@gmail.com      johP
Andrew AndrewV@gmail.com    andV

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

Entity  Cat1          EmailCat1                          Cat2              EmailCat2
A       Mary;Steve    maryD@gmail.com;steveR@gmail.com   Jacob             jacobB@gmail.com
B       Alex;John     AlexT@gmail.com;JohnP@gmail.com    Sally;Andrew      sallyD@gmail.com;AndrewV@gmail.com

any insights on how to go about it?

CodeMaster
  • 431
  • 4
  • 14
  • 4
    Fix your schema. See ["Is storing a delimited list in a database column really that bad?"](https://stackoverflow.com/questions/3653462/is-storing-a-delimited-list-in-a-database-column-really-that-bad) (Spoiler: Yes it is.). – sticky bit Apr 02 '21 at 14:19
  • I agree but the thing is that I am not maintaining the master database. I am only the end-user and I have no control over how it is being created currently. – CodeMaster Apr 02 '21 at 14:20
  • 2
    Your schema is horrible, and will not allow the tables to be JOINed properly. You'll find that the mess you've created with your table design is going to be nothing but a long string of headache after headache as you try to work with that data. You should find a good SQL tutorial or book and learn about database design before you bury yourself in this mess any deeper. – Ken White Apr 02 '21 at 14:21

1 Answers1

1

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',    'maryD@gmail.com'     ,'mryD'   from dual union all
select 'Steve',   'steveR@gmail.com'    ,'stvR'   from dual union all
select 'Jacob',   'jacobB@gmail.com'    ,'jacbb'   from dual union all
select 'Sally',   'sallyD@gmail.com'    ,'sallD'   from dual union all
select 'Alex',    'AlexT@gmail.com'     ,'alexT'   from dual union all
select 'John',    'JohnP@gmail.com'     ,'johP'   from dual union all
select 'Andrew',  'AndrewV@gmail.com'   ,'andV'   from dual
;

DB<>fiddle

Mahamoutou
  • 1,555
  • 1
  • 5
  • 11