【问题标题】:PL/SQL While/For LoopPL/SQL While/For 循环
【发布时间】:2020-03-06 22:24:52
【问题描述】:

我是一名 DBA,只是想编写一段代码来捕获 Oracle 中的用户权限并写入表。下面的代码适用于一个用户,但如果 ELSE 部分有多个用户,我会收到错误:“ORA-01422:精确提取返回的行数超过了请求的行数”。有道理,我意识到我需要一个 for/while 循环来处理多行,有人可以帮我吗?

'''

declare
   altersystem       varchar2(550);
   altersystemconcat varchar2(550);
begin
   select grantee
     into altersystem
     from dba_sys_privs
    where privilege = 'ALTER SYSTEM'
      and grantee not in ('SYS', 'SYSTEM');
   if altersystem = 'No rows selected'
   then
      insert into catch
      values
         ('900'
         ,'No custom users with the Alter System privilege.');
   else
      select concat('The following user/role has the Alter System privilege, revoke if not required: '
                   ,altersystem)
        into altersystemconcat
        from dual;
      insert into catch
      values
         ('100'
         ,altersystemconcat);
   end if;
end;
/

'''

【问题讨论】:

    标签: oracle plsql


    【解决方案1】:

    select ... INTO ... 要求返回恰好一行,否则会出现异常。通常你必须遍历一个游标,但你甚至可以用这样的一个命令来完成:

    BEGIN
    
        INSERT INTO catch
        SELECT 900, 'The following user/role has the Alter System privilege, revoke if not required: '||grantee 
        FROM dba_sys_privs 
        WHERE PRIVILEGE = 'ALTER SYSTEM' 
            AND grantee NOT IN ('SYS', 'SYSTEM');
    
       IF SQL%ROWCOUNT = 0 THEN
          INSERT INTO catch VALUES (100, 'No custom users with the Alter System privilege.');       
        END IF;
    END;
    

    【讨论】:

    • 这很完美,比我捏造的尝试要容易得多!谢谢。
    【解决方案2】:

    嗯...不,ELSESELECT 不会返回 too-many-rows。它从只有 1 行的 DUAL 中选择,所以 ...

    我怀疑这是第一个声明,select grantee into altersystem。如果有多个用户满足这些条件,则不能将它们全部放入声明为varchar2 的变量中。因此,是的 - 循环可能会有所帮助,它很简单。

    但是,为什么?为什么不简单地使用单个insert 插入所有那些违规者?像这样的:

    INSERT INTO catch
       SELECT '000', grantee
         FROM dba_sys_privs
        WHERE     privilege = 'ALTER SYSTEM'
              AND grantee NOT IN ('SYS', 'SYSTEM');
    

    【讨论】:

      【解决方案3】:

      这可以在单个 SQL 语句中完成 - 不需要 PL/SQL(除非您需要它作为存储过程):

      INSERT INTO catch (col1, col2) -- change col1 and col2 to the correct column_names in catch that you're inserting into
        WITH no_users AS (SELECT 100 no_user_present_id, 'No custom users with the Alter System privilege.' no_user_text FROM dual),
          users_there AS (SELECT 900 user_present_id, 'The following user/role has the Alter System privilege, revoke if not required: '||grantee user_there_text
                          FROM   dba_sys_privs
                          WHERE  PRIVILEGE = 'ALTER SYSTEM'
                          AND    grantee NOT IN ('SYS', 'SYSTEM'))
        SELECT COALESCE(ut.user_present_id, nu.no_user_present_id) ID,
               COALESCE(ut.user_there_text, nu.no_user_text) text
        FROM   no_users nu
               LEFT OUTER JOIN users_there ut ON 1 = 1;
      

      这通过使用外连接来工作,以便始终返回没有用户时的行。如果没有用户存在,则返回的行是默认行。如果存在具有指定授权的用户,您将获得这些用户返回的行。

      【讨论】:

        【解决方案4】:

        使用 listagg 函数可以连接结果字符串。

        注释掉插入语句,因为我没有 catch 表。改为打印输出。

        在没有找到行的情况下使用异常处理程序。

        declare
           altersystem       varchar2(550);
           altersystemconcat varchar2(550);
        begin
        
           select listagg(grantee, ', ') within group(order by grantee) "Grantee"
             into altersystem
             from dba_sys_privs
            where privilege = 'ALTER SYSTEM'
              and grantee not in ('SYS', 'SYSTEM');
        
          dbms_output.put_line('The following user/role has the Alter System privilege, revoke if not required: ' || altersystem);
          /*
         insert into catch
           values
              ('100'
              ,'The following user/role has the Alter System privilege, revoke if not required: ' || altersystem);
          */
        
        exception
           when no_data_found then
        
        dbms_output.put_line('No custom users with the Alter System privilege.');
        
        /*
              insert into catch
              values
                 ('900'
                 ,'No custom users with the Alter System privilege.');
        */
        end;
        /
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-07-30
          • 1970-01-01
          • 2013-12-22
          • 2016-04-22
          • 2014-06-19
          • 2018-03-21
          • 1970-01-01
          • 2013-07-21
          相关资源
          最近更新 更多