在 Oracle 存储过程中创建和使用序列 - 序列不存在

Creating and using Sequence in Oracle stored procedure - Sequence doesn't exist

    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;
    /

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

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

给出与您相同的错误,因为 table t1 不存在。所以 insert 语句是无效的。这是 PL/SQL.

编译期间的错误
create table t1 (c1 number);

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

exec createtest;

我收到错误提示 table 已经存在。但是编译器不知道我正在尝试再次创建相同的 table 所以它会在 运行 而不是编译期间返回。

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

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;

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

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 ....这是指你的序列

无论谁遇到这个问题,一个快速的解决方案是在声明过程时添加以下内容;

创建或替换程序 PROC_NAME AUTHID CURRENT_USER AS

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