【问题标题】:PL/SQL: Loop through attributes in a %ROWTYPEPL/SQL:循环遍历 %ROWTYPE 中的属性
【发布时间】:2016-07-24 05:55:36
【问题描述】:

我在 excel 中有一个矩阵,在第一列中我有用户名,在第二列和后续列中我有角色名称,如果用户是角色的成员,则为“Y”:

User Role1 Role2 Role3
Jon   Y      Y
Mary         Y    Y

我需要将其加载到 Oracle 数据库中。在数据库中,我已经有一个用户表:

UserId Username
1        Jon
2        Mary

我需要获取角色,即 Role1、Role2、Role3 并将其加载到角色表中:

roleId role
1      Role1
2      Role2
3      Role3

然后我需要将角色成员加载到角色映射表中:

UserId RoleId
1      1
1      2
2      2
2      3

到目前为止,我创建了一个具有 Column1、Column2、Column3 属性的表,并使用 SQL 开发人员在其中加载了 Excel 工作表,而没有使用 HEADER

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

从这里开始,我尝试使用存储过程循环遍历带有游标的表,并在其中找到 Column1 中的值“用户”,循环遍历该行中的属性并将其添加到角色表等.

但是,我无法在每个 %ROWTYPE 中循环遍历 CURSOR 中的属性。

这是一个好方法吗?如何循环遍历 %ROWTYPE 中的每个属性?

【问题讨论】:

  • 这是一个临时流程,还是会经常运行的流程?如果是后者,角色的数量会有所不同吗?
  • @Boneist,角色的数量将相当稳定,但我现在有大约 40 个角色。
  • 这会多久运行一次?一次性的?每周?日常的?更频繁?
  • @Boneist,可能每两周一次,角色几乎相同,即不会改变
  • 您使用的是什么版本的 Oracle?

标签: sql oracle stored-procedures plsql


【解决方案1】:

这就是我要做的(我在这里选择通用版本,因为您没有提及您正在使用的 Oracle 版本。如果您使用的是 11g 或更高版本,则可以使用UNPIVOT 命令):

我的示例插入语句的设置:

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

这两个语句都将列反转为行,然后在插入值之前选择相关值。

不需要循环或任何东西。

【讨论】:

  • 谢谢@Boneist,我将不得不消化这个并回复你。:)
猜你喜欢
  • 2023-03-19
  • 1970-01-01
  • 2014-09-27
  • 2023-01-11
  • 1970-01-01
  • 2021-07-30
  • 2020-12-27
  • 2016-05-26
  • 1970-01-01
相关资源
最近更新 更多