Oracle 游标总结+整理(转)

项目中需要使用到按规则生成序列号,开始的解决办法是根据条件取得最大ID号进行分解+1再合并的解决方案,后来发现如果两个客户同时操作的时候出现问题:添加的时候ID已经存在,原因是:A用户在访问取得第MAX(N)记录deID,但是还没有进行增加操作,这时,B用户也取得第MAX(N)记录deID,这是A进行添加操作同时,B也同时进行添加操作,那么B用户就会保存失败,我们开始的时候采用的解决方案是:(枷锁)在程序的方法上枷锁,采用单线程操作,实施结果:失败,客户等待时间长,后来我们采用绑定数据库的方案:编写存储过程,虽然绑定不怎么方便,但是执行效率要快很多。由于时间问题,没有做序列自动创建功能,欢迎各位大虾进行指点和评论,我们最后的方案如下:
在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 ;

下面为调用实例:
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);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值