这与以前的一个问题相关,
http://topic.csdn.net/u/20091209/16/85bab2c7-6bd8-464f-8a06-81d7f7bfb9de.html?472098105 。
很多人推荐我用merge,但是使用了merge后却发现新问题。
我有一个表,表的id用sequence生成。在merge一条新的数据时,我使用了sequence的NEXTVAL来生成新行的id值,然后我需要取得新行的id值返回。这时我发现在事务提交前和事务提交后,select得到的id值不一样。这是怎么回事呢?
代码见下:
procedure CategoryIWL3 (P_CATEGORY_NAME varchar2,O_idCategory out number) is
begin
begin
EXECUTE IMMEDIATE 'set transaction isolation level serializable';
MERGE INTO TA_CATEGORIES D USING (select P_CATEGORY_NAME as CATEGORY_NAME from dual) S on (D.CATEGORY_NAME=S.CATEGORY_NAME)
WHEN NOT MATCHED THEN INSERT (CATEGORY_ID,CATEGORY_NAME) VALUES (CATEGORIES_SEQ.NEXTVAL,S.CATEGORY_NAME);
SELECT CATEGORY_ID INTO O_idCategory FROM TA_CATEGORIES WHERE CATEGORY_NAME=P_CATEGORY_NAME ;
dbms_output.put_line('CATEGORY_ID=' || to_char(O_idCategory));
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
RAISE;
end;
COMMIT;
SELECT CATEGORY_ID INTO O_idCategory FROM TA_CATEGORIES WHERE CATEGORY_NAME=P_CATEGORY_NAME ;
dbms_output.put_line(' CATEGORY_ID=' || to_char(O_idCategory));
end CategoryIWL3;
表结构如下:
EXECUTE IMMEDIATE 'CREATE SEQUENCE CATEGORIES_SEQ START WITH 1 INCREMENT BY 1' ;
EXECUTE IMMEDIATE 'CREATE CLUSTER CL_CATEGORIES (CATEGORY_ID number(10))' ;
EXECUTE IMMEDIATE 'CREATE INDEX CI_CATEGORIES on CLUSTER CL_CATEGORIES' ;
EXECUTE IMMEDIATE 'CREATE TABLE TA_CATEGORIES(
CATEGORY_ID number(10) CONSTRAINT PK_CATEGORIES PRIMARY KEY NOT NULL ,
CATEGORY_NAME VARCHAR2(40) NOT NULL
)CLUSTER CL_CATEGORIES(CATEGORY_ID)' ;
EXECUTE IMMEDIATE 'CREATE INDEX I_CATEGORYNAME ON TA_CATEGORIES ( CATEGORY_NAME )' ;
http://topic.csdn.net/u/20091209/16/85bab2c7-6bd8-464f-8a06-81d7f7bfb9de.html?472098105 。
很多人推荐我用merge,但是使用了merge后却发现新问题。
我有一个表,表的id用sequence生成。在merge一条新的数据时,我使用了sequence的NEXTVAL来生成新行的id值,然后我需要取得新行的id值返回。这时我发现在事务提交前和事务提交后,select得到的id值不一样。这是怎么回事呢?
代码见下:
procedure CategoryIWL3 (P_CATEGORY_NAME varchar2,O_idCategory out number) is
begin
begin
EXECUTE IMMEDIATE 'set transaction isolation level serializable';
MERGE INTO TA_CATEGORIES D USING (select P_CATEGORY_NAME as CATEGORY_NAME from dual) S on (D.CATEGORY_NAME=S.CATEGORY_NAME)
WHEN NOT MATCHED THEN INSERT (CATEGORY_ID,CATEGORY_NAME) VALUES (CATEGORIES_SEQ.NEXTVAL,S.CATEGORY_NAME);
SELECT CATEGORY_ID INTO O_idCategory FROM TA_CATEGORIES WHERE CATEGORY_NAME=P_CATEGORY_NAME ;
dbms_output.put_line('CATEGORY_ID=' || to_char(O_idCategory));
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
RAISE;
end;
COMMIT;
SELECT CATEGORY_ID INTO O_idCategory FROM TA_CATEGORIES WHERE CATEGORY_NAME=P_CATEGORY_NAME ;
dbms_output.put_line(' CATEGORY_ID=' || to_char(O_idCategory));
end CategoryIWL3;
表结构如下:
EXECUTE IMMEDIATE 'CREATE SEQUENCE CATEGORIES_SEQ START WITH 1 INCREMENT BY 1' ;
EXECUTE IMMEDIATE 'CREATE CLUSTER CL_CATEGORIES (CATEGORY_ID number(10))' ;
EXECUTE IMMEDIATE 'CREATE INDEX CI_CATEGORIES on CLUSTER CL_CATEGORIES' ;
EXECUTE IMMEDIATE 'CREATE TABLE TA_CATEGORIES(
CATEGORY_ID number(10) CONSTRAINT PK_CATEGORIES PRIMARY KEY NOT NULL ,
CATEGORY_NAME VARCHAR2(40) NOT NULL
)CLUSTER CL_CATEGORIES(CATEGORY_ID)' ;
EXECUTE IMMEDIATE 'CREATE INDEX I_CATEGORYNAME ON TA_CATEGORIES ( CATEGORY_NAME )' ;
解决方案 »
- 执行存储过程报错!!!急!!!
- merge into 在对付一对多的关系时,有什么主意?
- 高手请进!!!!!
- oracle 的错误
- 再来一贴,我创建的存储过程PLS-00905: 对象 JTJ.CARINFO 无效,帮忙看看
- ==========日文系统oracle,编码插入日文,和解码到java,很正常,但能否这个日文系统同时插入中文(只有中文系统才有的中文,比如‘比赛)
- 配置菜问
- insert select 的问题 最高可给到400分
- 请问高手:如何配置并行服务器?
- 客户端安装oracle 91.0.2ids能否连接8.1.7的服务端?
- 在做从Access到Oracle的转换问一个关于日期函数的问题。
- 不支持过载的pl/sql 过程/函数
加上nocache后用一个值就取一个。
另外还有个奇怪的事情是,我用一个新的name值调用这个函数,到第一条“SELECT CATEGORY_ID INTO O_idCategory”的地方总会出错,报ORA-00512 : PL/SQL : numric or value error 。但是什么都不改,第二次执行又通过。这是怎么回事呢?
CATEGORIES_SEQ.NEXTVAL 放在一个变量里面,下面如果执行了insert,就是merge语句影响行数>0
(IF SQL%ROWCOUNT>0 THEN O_idCategory :=那个seqnextval的值; END IF;)
就把输出参数值改为那个变量,不用每次都根据CATEGORY_NAME去表里面搜啊。
第2次成功返回3,是因为返回0的那次,序列号也加了一次。SQL> create or replace procedure CategoryIWL3 (
2 P_CATEGORY_NAME in varchar2,
3 O_idCategory out number)
4 is
5 var_seq number(10);
6 begin
7 set transaction isolation level serializable;
8 begin
9 select CATEGORIES_SEQ.NEXTVAL into var_seq from dual;
10 MERGE INTO TA_CATEGORIES D USING (select P_CATEGORY_NAME as CATEGORY_NAME from dual) S on (D.CATEGORY_NAME=S.CATEGORY_NAME)
11 WHEN NOT MATCHED THEN INSERT (CATEGORY_ID,CATEGORY_NAME) VALUES (var_seq,S.CATEGORY_NAME);
12 IF SQL%ROWCOUNT>0 THEN
13 O_idCategory := var_seq;
14 else
15 O_idCategory :=0;
16 end if;
17 dbms_output.put_line('CATEGORY_ID=' || to_char(O_idCategory));
18 EXCEPTION WHEN OTHERS THEN
19 ROLLBACK;
20 O_idCategory :=0;
21 RAISE;
22 end;
23 COMMIT;
24 dbms_output.put_line(' CATEGORY_ID=' || to_char(O_idCategory));
25 end CategoryIWL3;
26 /过程已创建。SQL> variable a number;
SQL> exec CategoryIWL3('asdf',:a);PL/SQL 过程已成功完成。SQL> print a; A
----------
1SQL> select * from TA_CATEGORIES;CATEGORY_ID
-----------
CATEGORY_NAME
--------------------------------------------------------------------------------
1
asdf
SQL> exec CategoryIWL3('asdf',:a);PL/SQL 过程已成功完成。SQL> print a; A
----------
0SQL> exec CategoryIWL3('asfdf',:a);PL/SQL 过程已成功完成。SQL> print a; A
----------
3
这的确是一个解决办法,不过你的代码里面会对SEQUENCE的浪费比较严重吧,即SEQUENCE的连续性没法保证了。
另外,如果在你的代码的merge语句之后再select : SELECT CATEGORY_ID INTO O_idCategory FROM TA_CATEGORIES WHERE CATEGORY_NAME=P_CATEGORY_NAME ; 往往第一次执行会出错,报ora-06502 exception (numeric or value error) ,第二次执行又不出错,这你知道是为什么吗?
http://topic.csdn.net/u/20091217/11/7e04f479-17b1-44f8-9f52-3bf70f6ad411.html
sequence没必要保证连续,如果一定要连续,那么这么做:
1.除此存储过程外,不会有别的存储过程或sql或函数来select seq.nextVal,
2.此存储过程要保证被线性调用,即不能多线程同时调用,在前一个没有commit或rollback之前,另外不允许有别的调用,然后修改:在rollback之后,alter sequence 修改它的起始值为当前-1。
我想这与你的初衷可能有违背。。我修改后的应该不存在第一次出错,第二次不出错的问题啊,我N多存储过程都这么弄的,没出现过第一次出错第二次不出错至于后面加句select就会出错,搞不明白了
这个select into select出来的是个number,into的那个也是个number,应该不会出错
要不你在存储过程前面,as后面显式定义一个变量 var_no TA_CATEGORIES.CATEGORY_ID%TYPE;
保证它的类型和长度与select 里面的一致,
然后再 select CATEGORY_ID into var_no .....
下面再 out参数=var_no ,看看这样子会不会出错?