首页 文章

PL / SQL如果找到行,则执行此操作;否则做别的事

提问于
浏览
2

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

或者:

  • 用户对表没有任何权限

  • 用户具有基于直接授权的表的权限,如"grant select on table_ABC to user_123"

  • 用户具有基于授权角色的表的权限,如"grant read_only_role to user_123",其中read_only_role包含"grant select on table_ABC to read_only_role"

  • 用户基于SELECT ANY TABLE等系统特权对表具有特权

  • 用户基于DBA等包含SELECT ANY TABLE的角色对表具有特权 .

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

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

我想要发生的是:

  • 该过程循环遍历所有应用程序表

  • 该过程循环遍历所有用户

  • 如果存在直接授权,则variable1 ='TRUE'或使用SELECT INTO完成相同的操作

  • 如果存在角色授权,则variable2 ='TRUE'或使用SELECT INTO完成相同的操作

  • 如果有系统权限授予,变量3 ='TRUE'或使用SELECT INTO完成同样的事情

  • 如果有DBA角色授权,变量4 ='TRUE'或使用SELECT INTO完成同样的事情

  • 该过程为上面的每个项目打印表名,用户名,是/否 .

如何修改代码,以便如果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;

2 回答

  • 0

    使用以下技巧来避免异常

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

    或者你可以使用 SIGN(COUNT(grantee)) ,它返回 10

  • 0

    像这样的东西:

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

    结束;

    UPDATE

    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
    

    并且你可以在一个函数中有多个块,每个块都可以自己处理异常 .

相关问题