【问题标题】:PL/SQL If rows found do this; otherwise do something elsePL/SQL 如果找到的行执行此操作;否则做其他事情
【发布时间】:2015-05-19 20:13:39
【问题描述】:

我正在尝试在 pl/sql 中编写一个过程,它将告诉我谁对 Oracle 数据库中的所有应用程序表具有 SELECT、INSERT、UPDATE、DELETE 权限。

要么:

  1. 用户对表没有权限
  2. 用户基于直接授权(如“将 table_ABC 上的选择授予 user_123”)对表具有权限
  3. 用户基于授予的角色对表拥有特权,例如“grant read_only_role to user_123”,其中 read_only_role 包含“grant select on table_ABC to read_only_role”
  4. 用户拥有基于系统权限(如 SELECT ANY TABLE)的表权限
  5. 用户基于角色(如 DBA)对表拥有特权,其中包含 SELECT ANY TABLE。

现在,当我对用户或表名进行硬编码时,使用#2(例如)创建过程时,我不会遇到任何错误。但是当我尝试创建 1 个包含所有这些场景的过程时,我在 DATA_NOT_FOUND 时遇到了问题。

我可以处理异常,但程序随后退出。无论是否找到数据,我都无法使代码运行。 SQL%NOTFOUND 对我不起作用,因为在执行带有 SQL%NOTFOUND 的代码之前引发了 DATA_NOT_FOUND 异常。

我想要发生的是:

  1. 过程循环遍历所有应用程序表
  2. 程序循环遍历所有用户

  3. 如果有直接授权,variable1 = 'TRUE' 或使用 SELECT INTO 完成相同的操作

  4. 如果有角色授予,variable2 = 'TRUE' 或使用 SELECT INTO 完成相同的操作

  5. 如果有系统权限授予,variable3 = 'TRUE' 或使用 SELECT INTO 完成相同的操作

  6. 如果有 DBA 角色授权,variable4 = 'TRUE' 或使用 SELECT INTO 完成相同的操作

  7. 该过程为上述每个项目打印表名、用户名、是/否。

如何修改代码,如果 User_123 对 Table_ABC 具有 SELECT 权限,则 variable1 = 'TRUE',否则 variable1 = 'FALSE'?如果 dba_tab_privs 中没有 User_123 的记录,则不应引发 DATA_NOT_FOUND 异常。

非常感谢您。


DECLARE
  by_tab_priv varchar(20);

BEGIN

  dbms_output.enable(1000000);

  FOR x IN ( SELECT table_name
           FROM dba_tables
           WHERE owner IN ('NIKUP')
           ORDER BY table_name )
  LOOP

    BEGIN

      FOR y IN ( SELECT username from dba_users
           ORDER BY username)
      LOOP


        SELECT grantee 
        INTO by_tab_priv 
        FROM dba_tab_privs 
        WHERE    grantee=y.username 
             and table_name=x.table_name 
             and privilege in ('SELECT')
        MINUS
        SELECT granted_role 
        FROM dba_role_privs 
        WHERE granted_role in (
                SELECT grantee 
                FROM dba_tab_privs 
                WHERE     grantee=y.username 
                      and table_name=x.table_name 
                      and privilege in ('SELECT'));

        BEGIN
          dbms_output.put_line(y.username || ' ' || by_tab_priv);
        END;

       END LOOP;
     END;
   END LOOP;
   EXCEPTION
    WHEN NO_DATA_FOUND THEN
      by_tab_priv:='FALSE';
 END;

【问题讨论】:

    标签: oracle plsql


    【解决方案1】:

    类似这样的:

    begin
      select ... into ;
      var1 :=TRUE;
    exception
      when NO_DATA_FOUND then  -- controlling the case with no_data_found
        var1 := FAlSE;
    

    结束;

    更新

      LOOP
       BEGIN
        SELECT grantee 
        INTO by_tab_priv 
        FROM dba_tab_privs 
        WHERE    grantee=y.username 
             and table_name=x.table_name 
             and privilege in ('SELECT')
        MINUS
        SELECT granted_role 
        FROM dba_role_privs 
        WHERE granted_role in (
                SELECT grantee 
                FROM dba_tab_privs 
                WHERE     grantee=y.username 
                      and table_name=x.table_name 
                      and privilege in ('SELECT'));
    
    
        dbms_output.put_line(y.username || ' ' || by_tab_priv);
    
       EXCEPTION
        WHEN NO_DATA_FOUND THEN
         by_tab_priv:='FALSE';
       END;
    
     END LOOP;
    

    异常只链接到循环内的块,它不是全局异常

    块的结构如下:

    BEGIN
    EXCEPTION 
    END
    

    你可以在一个函数内有多个块,每个块都做自己的异常处理。

    【讨论】:

    • 我尝试使用上面的代码来实现这个解决方案。这只是我稍后会完善的第一次尝试,但同样的事情正在发生。程序执行成功,但那只是因为当no_data_found时,它退出了。
    • 否,异常用作流控制,如果 data_found (select ... into) then do_something else_if not_data_found then do_something_else.
    • 对于某些用户名,dba_tab_privs 中有数据。对于其他人来说,没有。进入异常块后如何让它返回循环并继续处理记录?我可以在异常块中添加 GOTO 语句吗?
    • 非常感谢瓦伦丁。我也在重写我的查询。我会尽快发布。
    【解决方案2】:

    使用以下技巧来避免异常

    SELECT NVL(MAX(grantee), 'FALSE')
    INTO by_tab_priv
    FROM (
      SELECT
      ...
      MINUS
      SELECT
      ...
    )
    

    您也可以使用SIGN(COUNT(grantee)),它返回10

    【讨论】:

    • 非常感谢帕维尔。两种解决方案都有效。如果我想保留计数的记录,也可以在 var1 中选择 count(*),然后使用 if/else 逻辑工作,以防用户被授予 2 个以上具有重叠权限的角色。
    • 如果 SELECT INTO 语句未能返回一行,无论您是否在下一行检查 SQL%NOTFOUND,PL/SQL 都会引发预定义的异常 NO_DATA_FOUND。但是,调用 SQL 聚合函数的 SELECT INTO 语句永远不会引发 NO_DATA_FOUND,因为这些函数总是返回值或空值。在这种情况下,SQL%NOTFOUND 产生 FALSE。
    猜你喜欢
    • 1970-01-01
    • 2013-01-19
    • 2021-10-27
    • 2013-09-04
    • 2017-06-08
    • 2021-02-10
    • 2016-08-20
    • 2023-03-09
    • 2014-02-17
    相关资源
    最近更新 更多