在 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 语句将编译并 运行 成功。
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 语句将编译并 运行 成功。