【问题标题】:Creating and using Sequence in Oracle stored procedure - Sequence doesn't exist在 Oracle 存储过程中创建和使用序列 - 序列不存在
【发布时间】:2017-02-22 07:30:09
【问题描述】:
    DECLARE
      v_emp_id NUMBER;
      empid    NUMBER;
      stmt     VARCHAR2(1000);
    BEGIN
      SELECT MAX(emp_id) + 1 INTO v_emp_id FROM employees;
      BEGIN
        dbms_output.put_line(v_emp_id );
        stmt := 'CREATE SEQUENCE emp_seq start with ' ||v_emp_id|| ' increment by 1 NOCYCLE';
        EXECUTE IMMEDIATE stmt;
        COMMIT;
      END;
      insert into emp_new select emp_seq.nextval,empname from (select * from employee where active = 0);
      dbms_output.put_line(empid);
    END;
    /

执行上述程序时,出现以下错误 ORA-06550:第 13 行,第 10 列: PL/SQL: ORA-02289: 序列不存在 ORA-06550:第 13 行,第 3 列: PL/SQL:忽略 SQL 语句

但是当执行下面的过程时,它是成功的并且创建了序列。

    DECLARE
      v_emp_id NUMBER;
      empid    NUMBER;
      stmt     VARCHAR2(1000);
    BEGIN
      SELECT MAX(emp_id) + 1 INTO v_emp_id FROM employees;
      BEGIN
        dbms_output.put_line(v_emp_id );
        stmt := 'CREATE SEQUENCE emp_seq start with ' ||v_emp_id|| ' increment by 1 NOCYCLE';
        EXECUTE IMMEDIATE stmt;
        COMMIT;
      END;
      dbms_output.put_line(empid);
    END;
    /

【问题讨论】:

    标签: oracle stored-procedures plsql dynamic-sql


    【解决方案1】:

    在编译期间不存在时间序列,因此编译器返回错误。立即执行将在运行时执行,但编译器不知道它会创建您稍后在代码中调用的序列。

    create or replace procedure createtest as
    begin 
    execute immediate 'create table t1 (c1 number)';
    insert into t1 values (1);
    end;
    /
    

    给出与您相同的错误,因为表 t1 不存在。所以插入语句无效。这是 PL/SQL 编译过程中的错误。

    create table t1 (c1 number);
    

    之后我可以创建程序,但是当我这样做时:

    exec createtest;
    

    我收到表已经存在的错误。但是编译器不知道我正在尝试再次创建同一个表,因此它将在运行时而不是在编译期间返回。

    如果你真的需要这样做,请这样做:

    create or replace procedure createtest as
    begin 
    execute immediate 'create table t1 (c1 number)';
    execute immediate 'insert into t1 values (1)';
    end;
    /
    

    在你的情况下:

    execute immediate 'SELECT emp_seq.nextval FROM dual' INTO empid;
    

    [编辑] 我的理解是您要确保将序列设置为 max(empid),因此请不要尝试在过程中创建它。创建序列一次,然后在程序主体中执行:

    select max(empid) into maxempid from employee;
    select emp_seq.currval into maxseq from dual;
    if(empid-maxseq>0) then
    execute immediate 'alter sequence emp_seq increment by ' || empid-maxseq;
    end if;
    

    【讨论】:

    • 谢谢 :) 我在 insert 中使用 seq 和 select 语句。关于如何做的任何想法?抱歉,我对 oracle 程序知之甚少
    • 立即执行 'SELECT emp_seq.nextval FROM dual' INTO empid;这是如何在 select 中使用新创建的序列并将值返回给 empid。
    • 插入emp_new select (emp_seq.nextval,empname) from employee;
    • 我已经更新了所提出的问题。可以看看吗
    • 您可以使用从序列中选择值的光标来获取它,但这确实是不必要的复杂化。请创建一次序列。然后在里面创建没有创建序列语句的过程。
    【解决方案2】:

    您应该在创建过程之前创建静态序列。

    DROP SEQUENCE emp_seq
    /
    
    BEGIN
      SELECT MAX(emp_id) + 1 INTO v_emp_id FROM employees;
      dbms_output.put_line(v_emp_id );
      execute immediate 'CREATE SEQUENCE emp_seq start with ' ||v_emp_id|| ' increment by 1 NOCYCLE';
    END;
    /
    

    然后 CREATE OR REPLACE FUNCTION/PROCEDURE/PACKAGE .... 指的是您的序列

    【讨论】:

      【解决方案3】:

      遇到这个问题的人,一个快速的解决方案是在声明过程时在下面添加;

      创建或替换 PROCEDURE PROC_NAME AUTHID CURRENT_USER AS

      在此声明后,EXECUTE IMMEDIATE 语句将编译并运行成功。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-07
        • 1970-01-01
        • 2021-09-19
        • 1970-01-01
        相关资源
        最近更新 更多