Oracle 游标总结+整理
项目中需要使用到按规则生成序列号,开始的解决办法是根据条件取得最大ID号进行分解+1再合并的解决方案,后来发现如果两个客户同时操作的时候出现问题:添加的时候ID已经存在,原因是:A用户在访问取得第MAX(N)记录deID,但是还没有进行增加操作,这时,B用户也取得第MAX(N)记录deID,这是A进行添加操作同时,B也同时进行添加操作,那么B用户就会保存失败,我们开始的时候采用的解决方案是
:(枷锁)在程序的方法上枷锁,采用单线程操作,实施结果:失败,客户等待时间长,后来我们采用绑定数据库的方案:编写存储过程,虽然绑定不怎么方便,但是执行效率要快很多。由于时间问题,没有做序列自动创建功能,欢迎各位大虾进行指点和评论,我们最后的方案如下:
在oracle里面编写了2个基本做基本处理的自定义函数:
下面为调用实例:
select
fun_config_glide_num(
'
TabMachineType
'
,
'
FAC_CODE
'
)
as
CN
FROM
dual;
下面是表流水帐号表结构
--
Create table
create
table
LSZH_TABLE
(
LSZH_CNAME
CHAR
(
20
)
not
null
,
LSZH_TNAME
CHAR
(
20
),
LSZH_COLUMN
CHAR
(
20
)
not
null
,
LSZH_MARK
CHAR
(
20
),
LSZH_DATETYPE
CHAR
(
10
),
LSZH_NUM
CHAR
(
3
)
default
4
)
![]()
--
Add comments to the columns
comment
on
column
LSZH_TABLE.LSZH_CNAME
is
'
流水帐号类名
'
;
comment
on
column
LSZH_TABLE.LSZH_TNAME
is
'
流水帐对应的数据库表名
'
;
comment
on
column
LSZH_TABLE.LSZH_COLUMN
is
'
流水帐号类别标识列
'
;
comment
on
column
LSZH_TABLE.LSZH_MARK
is
'
流水帐号类别标识对应的字符
'
;
comment
on
column
LSZH_TABLE.LSZH_DATETYPE
is
'
时间作为流水号的排列次序
'
;
comment
on
column
LSZH_TABLE.LSZH_NUM
is
'
流水码长度
'
;
--
Create/Recreate primary, unique and foreign key constraints
alter
table
LSZH_TABLE
add
constraint
PK_LSZH_TABLE
primary
key
(LSZH_COLUMN, LSZH_CNAME)
参考资料:
DBMS_SQL系统包提供了很多函数及过程,现在简要阐述其中使用频率较高的几种:
function open_cursor:打开一个动态游标,并返回一个整型;
procedure close_cursor(c in out integer);关闭一个动态游标,参数为open_cursor所打开的游标;
procedure parse(c in integer, statement in varchar2, language_flag in integer):对动态游标所提供的sql语句进行解析,参数C表示游标,statement为sql语句,language-flag为解析sql语句所用oracle版本,一般有V6,V7跟native(在不明白所连database版本时,使用native);
procedure define_column(c in integer, position in integer, column any datatype, [column_size in integer]):定义动态游标所能得到的对应值,其中c为动态游标,positon为对应动态sql中的位置(从1开始),column为该值所对应的变量,可以为任何类型,column_size只有在column为定义长度的类型中使用如VARCHAR2,CHAR等(该过程有很多种情况,此处只对一般使用到的类型进行表述);
function execute(c in integer):执行游标,并返回处理一个整型,代表处理结果(对insert,delete,update才有意义,而对select语句而言可以忽略);
function fetch_rows(c in integer):对游标进行循环取数据,并返回一个整数,为0时表示已经取到游标末端;
procedure column_value(c in integer, position in integer, value):将所取得的游标数据赋值到相应的变量,c为游标,position为位置,value则为对应的变量;
procedure bind_variable(c in integer, name in varchar2, value):定义动态sql语句(DML)中所对应字段的值,c为游标,name为字段名称,value为字段的值;
以上是在程序中经常使用到的几个函数及过程,其他函数及过程请参照oracle所提供定义语句dbmssql.sql
对于一般的select操作,如果使用动态的sql语句则需要进行以下几个步骤:
open cursor--->parse--->define column--->excute--->fetch rows--->close cursor;
而对于dml操作(insert,update)则需要进行以下几个步骤:
open cursor--->parse--->bind variable--->execute--->close cursor;
对于delete操作只需要进行以下几个步骤:
open cursor--->parse--->execute--->close cursor;
序列sequence:
http:
//
www.examda.com
/
Oracle
/
关于Oracle的序列(Sequence)使用序列是一数据库对象,利用它可生成唯一的整数。一般使用序列自动地生成主键值。对我们程序员来讲,精力时间有限,我们只学最有用的知识。大家请看:
1
) 建立序列命令
CREATE
SEQUENCE
[
user.
]
sequence_name
[
increment by n
]
[
start with n
]
[
maxvalue n | nomaxvalue
]
[
minvalue n | nominvalue
]
;
[
NOCYCLE
]
--
INCREMENT
BY
: 指定序列号之间的间隔,该值可为正的或负的整数,但不可为0.序列为升序。忽略该子句时,缺省值为1.
START
WITH
:指定生成的第一个序列号。在升序时,序列可从比最小值大的值开始,缺省值为序列的最小值。对于降序,序列可由比最大值小的值开始,缺省值为序列的最大值。
MAXVALUE:指定序列可生成的最大值。
NOMAXVALUE:为升序指定最大值为1027,为降序指定最大值为
-
1
.
MINVALUE:指定序列的最小值。
NOMINVALUE:为升序指定最小值为1.为降序指定最小值为
-
1026
.
NOCYCLE:一直累加,不循环
2
) 更改序列命令
ALTERSEQUENCE
[
user.
]
sequence_name
[
INCREMENT BY n
]
[
MAXVALUE n| NOMAXVALUE
]
[
MINVALUE n | NOMINVALUE
]
;
修改序列可以:修改未来序列值的增量。
设置或撤消最小值或最大值。
改变缓冲序列的数目。
指定序列号是否是有序。
注意:
1
,第一次NEXTVAL返回的是初始值
2
,可以alter除start至以外的所有sequence参数。如果想要改变start值,必须
drop
sequence 再 re
-
create
.
3
) 删除序列命令
DROP
SEQUENCE
[
user.
]
sequence_name;
用于从数据库中删除一序列。
4
)牛刀小试
4.1
)创建一个序列号的语句:
--
Create sequence
create
sequence NCME_QUESTION_SEQ
minvalue
1
maxvalue
999999999999
start
with
1
increment
by
1
nocache;
//////////////////////////////
4.2
)SQL中取序列号的用法:
SELECT
NCME_QUESTION_SEQ.nextval
FROM
dual
SELECT
NCME_QUESTION_SEQ.CURRVAL
FROM
dual
SELECT
NCME_QUESTION_SEQ.nextval
FROM
dual
SELECT
NCME_QUESTION_SEQ.CURRVAL
FROM
dual
注意:在使用序列的时候,有时需要有用户名,就像这样:
insert
into
system.CONSERVATOR(CONSERVATORNAME,CONPASS,CONTRUENAME,CONSEX,CONID)
values
(
'
JG
'
,
'
123456
'
,
'
000
'
,
0
, system.CONID.nextval);
参考资料链接:
关于DBMS_SQL包,动态SQL语句的问题
oracle 隐式游标,显示游标,游标循环,动态SELECT语句和动态游标,异常处理,自定义异常
oracle 创建,删除存储过程,参数传递,创建,删除存储函数,存储过程和函数的查看,包,系统包
几种使用动态SQL做游标的总结
关于动态SQL的使用
oracle创建存储过程
oracle创建函数,存储过程,视图以及for循环语法
oracle自定义函数
在oracle里面编写了2个基本做基本处理的自定义函数:
create
or
replace
function
fun_config_glide_num(p_class
varchar2
,
p_column varchar2 )
/* *
* 流水帐号配置_oracle
* author:ai bo 2010.02.23
* p_table varchar2 表名
* p_website varchar2 自定义开头字符
*/
return varchar2 as
v_curId integer ;
-- v_seq varchar2(50);
-- v_seq_value number;
v_sql varchar2 ( 200 );
v_ret number ( 3 );
v_num varchar2 ( 20 );
p_table varchar2 ( 30 );
p_website varchar2 ( 20 );
p_length varchar2 ( 3 );
t_class varchar2 ( 20 );
t_column varchar2 ( 20 );
begin
t_class : = p_class;
t_column : = p_column;
v_sql : = ' SELECT lszh_tname,lszh_mark,lszh_num FROM lszh_table WHERE lszh_cname = ' ||
chr( 39 ) || t_class || chr( 39 ) || '
and lszh_column= ' || chr( 39 ) || t_column || chr( 39 ) || '' ;
v_curId : = DBMS_SQL.OPEN_CURSOR; -- 为处理打开光标
DBMS_SQL.PARSE(v_curId, v_Sql, DBMS_SQL.native); -- 分析语句
DBMS_SQL.DEFINE_COLUMN(v_curId, 1 , p_table, 128 ); -- 定义动态游标所能得到的对应值
DBMS_SQL.DEFINE_COLUMN(v_curId, 2 , p_website, 128 );
DBMS_SQL.DEFINE_COLUMN(v_curId, 3 , p_length, 128 );
v_ret : = DBMS_SQL. EXECUTE (v_curId); -- 执行语句
loop
if DBMS_SQL.FETCH_ROWS(v_curId) = 0 then
exit ;
end if ;
DBMS_SQL.COLUMN_VALUE(v_curId, 1 , p_table); -- 将所取得的游标数据赋值到相应的变量
-- DBMS_OUTPUT.PUT_LINE(p_table);
DBMS_SQL.COLUMN_VALUE(v_curId, 2 , p_website);
-- DBMS_OUTPUT.PUT_LINE(p_website);
DBMS_SQL.COLUMN_VALUE(v_curId, 3 , p_length);
-- DBMS_OUTPUT.PUT_LINE(p_length);
end loop;
DBMS_SQL.CLOSE_CURSOR(v_curid); -- 关闭一个动态游标
v_num : = fun_get_glide_num(trim(p_table), trim(p_website), trim(p_length));
return v_num;
end ;
create or replace function fun_get_glide_num(p_table varchar2 ,p_website varchar2 ,p_length number )
/* *
* 流水帐号创建oracle版本
* author : ai bo 2010.02.23
* p_table varchar2 表名
* p_website varchar2 自定义开头字符
*/
return varchar2 as
v_seq varchar2 ( 50 );
v_seq_value number ;
v_sql varchar2 ( 200 );
v_num varchar2 ( 20 );
begin
v_seq : = ' seq_ ' || p_table;
v_sql : = ' select ' || v_seq || ' .nextval from dual ' ;
dbms_output.put_line(v_sql);
execute immediate v_sql
into v_seq_value;
select lpad(v_seq_value, p_length, ' 0 ' ) into v_num from dual;
v_num : = p_website || v_num;
return v_num;
end ;
p_column varchar2 )
/* *
* 流水帐号配置_oracle
* author:ai bo 2010.02.23
* p_table varchar2 表名
* p_website varchar2 自定义开头字符
*/
return varchar2 as
v_curId integer ;
-- v_seq varchar2(50);
-- v_seq_value number;
v_sql varchar2 ( 200 );
v_ret number ( 3 );
v_num varchar2 ( 20 );
p_table varchar2 ( 30 );
p_website varchar2 ( 20 );
p_length varchar2 ( 3 );
t_class varchar2 ( 20 );
t_column varchar2 ( 20 );
begin
t_class : = p_class;
t_column : = p_column;
v_sql : = ' SELECT lszh_tname,lszh_mark,lszh_num FROM lszh_table WHERE lszh_cname = ' ||
chr( 39 ) || t_class || chr( 39 ) || '
and lszh_column= ' || chr( 39 ) || t_column || chr( 39 ) || '' ;
v_curId : = DBMS_SQL.OPEN_CURSOR; -- 为处理打开光标
DBMS_SQL.PARSE(v_curId, v_Sql, DBMS_SQL.native); -- 分析语句
DBMS_SQL.DEFINE_COLUMN(v_curId, 1 , p_table, 128 ); -- 定义动态游标所能得到的对应值
DBMS_SQL.DEFINE_COLUMN(v_curId, 2 , p_website, 128 );
DBMS_SQL.DEFINE_COLUMN(v_curId, 3 , p_length, 128 );
v_ret : = DBMS_SQL. EXECUTE (v_curId); -- 执行语句
loop
if DBMS_SQL.FETCH_ROWS(v_curId) = 0 then
exit ;
end if ;
DBMS_SQL.COLUMN_VALUE(v_curId, 1 , p_table); -- 将所取得的游标数据赋值到相应的变量
-- DBMS_OUTPUT.PUT_LINE(p_table);
DBMS_SQL.COLUMN_VALUE(v_curId, 2 , p_website);
-- DBMS_OUTPUT.PUT_LINE(p_website);
DBMS_SQL.COLUMN_VALUE(v_curId, 3 , p_length);
-- DBMS_OUTPUT.PUT_LINE(p_length);
end loop;
DBMS_SQL.CLOSE_CURSOR(v_curid); -- 关闭一个动态游标
v_num : = fun_get_glide_num(trim(p_table), trim(p_website), trim(p_length));
return v_num;
end ;
create or replace function fun_get_glide_num(p_table varchar2 ,p_website varchar2 ,p_length number )
/* *
* 流水帐号创建oracle版本
* author : ai bo 2010.02.23
* p_table varchar2 表名
* p_website varchar2 自定义开头字符
*/
return varchar2 as
v_seq varchar2 ( 50 );
v_seq_value number ;
v_sql varchar2 ( 200 );
v_num varchar2 ( 20 );
begin
v_seq : = ' seq_ ' || p_table;
v_sql : = ' select ' || v_seq || ' .nextval from dual ' ;
dbms_output.put_line(v_sql);
execute immediate v_sql
into v_seq_value;
select lpad(v_seq_value, p_length, ' 0 ' ) into v_num from dual;
v_num : = p_website || v_num;
return v_num;
end ;
下面为调用实例:
下面是表流水帐号表结构
参考资料:
关于DBMS_SQL包,动态SQL语句的问题
oracle 隐式游标,显示游标,游标循环,动态SELECT语句和动态游标,异常处理,自定义异常
oracle 创建,删除存储过程,参数传递,创建,删除存储函数,存储过程和函数的查看,包,系统包
几种使用动态SQL做游标的总结
关于动态SQL的使用
oracle创建存储过程
oracle创建函数,存储过程,视图以及for循环语法
oracle自定义函数