1

I have a matrix in excel where in the first column I have user names and in the second and subsequent columns I have role names and a 'Y' if a user is a member of the role:

User Role1 Role2 Role3
Jon   Y      Y
Mary         Y    Y

I need to load this into an Oracle database. In the database I already have a table for users:

UserId Username
1        Jon
2        Mary

I need to take the roles i.e. Role1, Role2, Role3 and load it into a roles table:

roleId role
1      Role1
2      Role2
3      Role3

And then I need to load the role memberships into a role mapping table:

UserId RoleId
1      1
1      2
2      2
2      3

So far I created a table with Column1,Column2,Column3 attributes and loaded the Excel sheet in there with SQL developer without using the HEADER!

Column1 Column2 Column3 Column4
User    Role1   Role2   Role3
Jon     Y       Y
Mary            Y       Y

From here I'm trying to use a stored procedure to loop through the table with a cursor and where I find the value 'User' in Column1, loop through the attributes in that row and add those to the roles table, etc.

However I'm having trouble looping through the attributes within the CURSOR in each %ROWTYPE.

Is this a good approach? How can I loop through each attribute in a %ROWTYPE?

5
  • 1
    is this an ad-hoc process, or something that will be run fairly often? If the latter, could the number of roles vary? Commented Apr 4, 2016 at 15:37
  • @Boneist, the number of roles will be fairly static, I have however about 40 roles right now. Commented Apr 4, 2016 at 15:45
  • 1
    And how often would this get run? A one-off? Weekly? Daily? More frequently? Commented Apr 4, 2016 at 15:49
  • @Boneist, probably bi-weekly, roles would be pretty much the same i.e. wouldn't change Commented Apr 4, 2016 at 15:53
  • And what version of Oracle are you using? Commented Apr 4, 2016 at 15:54

1 Answer 1

2

This is what I'd do (I'm going for a generalised version here, since you didn't mention your Oracle version you're using. If you're on 11g or above, you could do the unpivoting using the UNPIVOT command):

Setup for my example insert statements:

create table data_to_upload as
select 'User' col1, 'Role1' col2, 'Role2' col3, 'Role3' col4 from dual union all
select 'Jon' col1, 'Y' col2, 'Y' col3, null col4 from dual union all
select 'Mary' col1, null col2, 'Y' col3, 'Y' col4 from dual;

create table test_users as
select 1 userid, 'Jon' username from dual union all
select 2 userid, 'Mary' username from dual;

create table test_roles (roleid number,
                         rolename varchar2(20));

create sequence test_roles_seq
  start with 1
  maxvalue 9999
  minvalue 1
  nocycle
  cache 20;

create table test_user_roles (userid number, roleid number);

Insert Roles:

insert into test_roles
select test_roles_seq.nextval roleid,
       case when dummy.id = 1 then (select col2 from data_to_upload where col1 = 'User')
            when dummy.id = 2 then (select col3 from data_to_upload where col1 = 'User')
            when dummy.id = 3 then (select col4 from data_to_upload where col1 = 'User')
       end rolename
from   data_to_upload dto
       cross join (select level id
                   from   dual
                   connect by level <= 3 -- number of roles being imported
                  ) dummy
where col1 = 'User';

commit;

Insert User Roles:

insert into test_user_roles
select tu.userid,
       case when dummy.id = 1 then (select tr.roleid from data_to_upload dtu2 inner join test_roles tr on (dtu2.col2 = tr.rolename) where dtu2.col1 = 'User')
            when dummy.id = 2 then (select tr.roleid from data_to_upload dtu2 inner join test_roles tr on (dtu2.col3 = tr.rolename) where dtu2.col1 = 'User')
            when dummy.id = 3 then (select tr.roleid from data_to_upload dtu2 inner join test_roles tr on (dtu2.col4 = tr.rolename) where dtu2.col1 = 'User')
       end roleid
from   data_to_upload dtu
       inner join test_users tu on (dtu.col1 = tu.username)
       inner join (select level id
                   from   dual
                   connect by level <= 3 -- number of roles being imported
                  ) dummy on ((dummy.id = 1 and dtu.col2 = 'Y')
                              or (dummy.id = 2 and dtu.col3 = 'Y')
                              or (dummy.id = 3 and dtu.col4 = 'Y'))
where col1 != 'User';

commit;

Both statements unpivot the columns into rows and then select the relevant values before inserting the values.

No need for loops or anything.

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

1 Comment

Thanks @Boneist I'll have to digest this and get back to you.:)

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.