带有 IF-THEN-ELSE 的 Oracle 过程产生错误

Oracle Procedure with an IF-THEN-ELSE produces error

我在 Oracle 中创建了这个过程,以根据存储在营销 table 的等级列中的等级为用户分配角色。但是,当我 运行 它时,我得到了错误。

初始问题

CREATE OR REPLACE PROCEDURE proc_assign_role IS
    vn_grade NUMBER(5);

CURSOR cur_user_grade IS
    SELECT grade, username
    FROM marketing
    WHERE grade BETWEEN 1 AND 3;
BEGIN
    FOR rec_cur_user_grade IN cur_user_grade
    vn_grade:=
    IF grade= 1
        THEN 
            GRANT ROLE admin_staff;
        ELSIF grade= 2 THEN
            GRANT ROLE marketing_staff;
        ELSIF grade= 3 THEN
            GRANT ROLE event_staff;
    END IF;
    DBMS_OUTPUT.PUT_LINE(username||'YOU ARE A GRADE '||vn_grade|| 'USER');
END proc_assign_role;
/

这是我得到的错误:

ERROR at line 11: PLS-00103: Encountered the symbol "VN_GRADE" when expecting one of the following:

   . ( * @ % & - + / at loop mod remainder range rem ..
    || multiset
1. CREATE OR REPLACE PROCEDURE proc_assign_role IS
2.  vn_grade NUMBER(5); 

vn_grade:=

您需要为该行分配一个值,或者删除它。您不能将 IF 语句分配给数字变量。可能摆脱它,然后更改您的 IF 语句以查看光标的成绩。您还需要结束循环。

此外,您不能直接在 PL/SQL 代码块中执行授权。您必须为此使用立即执行语句。而且您必须告诉它您将角色授予谁。

FOR rec_cur_user_grade IN cur_user_grade LOOP
    IF rec_cur_user_grade.grade= 1 THEN 
        execute immediate 'GRANT ROLE admin_staff to ' || rec_cur_user_grade.username;
    ELSIF rec_cur_user_grade.grade= 2 THEN
        execute immediate 'GRANT ROLE marketing_staff to ' || rec_cur_user_grade.username;
    ELSIF rec_cur_user_grade.grade= 3 THEN
        execute immediate 'GRANT ROLE event_staff to ' || rec_cur_user_grade.username;
    END IF;
DBMS_OUTPUT.PUT_LINE(username||'YOU ARE A GRADE '||rec_cur_user_grade.grade|| 'USER');
END LOOP;

grant 是 DDL,因此不能直接在 PL/SQL 中使用。为了实现这一点,需要动态执行 DDL,使用 execute immediately。此外,grant 始终要求您指定角色的接收者。结果将是这样的:

execute immediate 'GRANT ROLE admin_staff to ' || rec_cur_user_grade.username;

一个 ORA-00990: missing or invalid privilege 错误是相当自我描述的:过程的所有者没有必要的权限来执行该过程正在尝试的操作。

这里最有可能的罪魁祸首是角色:不能在过程中使用角色授予的权限。您应该采取的第一步是确保程序的所有者已被明确授予管理所涉及角色的权限。

我发现了一些会阻止它工作的东西:

  • 在您的 FOR 语句之后,没有 LOOP 语句(这是错误所抱怨的)。在你的 DBMS_OUTPUT.
  • 之后也没有 END LOOP
  • vn_grade 后跟 := 赋值运算符,但未向其赋值。
  • GRANT 语句被编写为裸 DDL,这在 PL/SQL 中是不允许的。它们需要包裹在 EXECUTE IMMEDIATE.
  • gradeusername 需要由游标变量限定(例如,rec_cur_user_grade.graderec_cur_user_grade.username)。

尝试这样的事情(作为匿名块而不是过程运行,并使用隐式游标):

BEGIN
    FOR rec_cur_user_grade IN (
        SELECT grade, username
        FROM marketing
        WHERE grade BETWEEN 1 AND 3
    )
    LOOP
        CASE rec_cur_user_grade.grade
            WHEN 1 THEN
                EXECUTE IMMEDIATE 'GRANT ROLE admin_staff TO ' || rec_cur_user_grade.username;
            WHEN 2 THEN
                EXECUTE IMMEDIATE 'GRANT ROLE marketing_staff TO ' || rec_cur_user_grade.username;
            WHEN 3 THEN
                EXECUTE IMMEDIATE 'GRANT ROLE event_staff TO ' || rec_cur_user_grade.username;
        END CASE;
        DMBS_OUTPUT.PUT_LINE(rec_cur_user_grade.username || ' YOU ARE A GRADE ' || rec_cur_user_grade.grade || ' USER');
    END LOOP;
END;
/