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   [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?

3
  • 4
    Fix your schema. See "Is storing a delimited list in a database column really that bad?" (Spoiler: Yes it is.). Commented Apr 2, 2021 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. Commented Apr 2, 2021 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. Commented Apr 2, 2021 at 14:21

1 Answer 1

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',    '[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

Sign up to request clarification or add additional context in comments.

1 Comment

thnx. I completely understand that the base tables are poorly designed and must be modified.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.