第一个oracle存储过程,我的第一个Oracle存储过程

这篇博客详细介绍了如何在Oracle数据库中编写一个存储过程,该过程从特定表中检索数据,将结果转换为XML格式,并将生成的文件通过FTP上传到服务器。内容涉及到文件命名规范、XML格式定义、游标使用、文件操作以及异常处理等关键技术点。
摘要由CSDN通过智能技术生成

这个存储过程的用意是从数据库表中检索,将检索结果按照指定格式写成XML文件,上传到服务器。

库表名称:WL_AL_OPERATOR_NUMSECTION

XML文件名称:ECID_OrdSub_YYYYMMDDHHMISS_BBOSS.NNN

*

其中NNN是文件序列号,从000至999。每天EC发送的文件以000开始,如果当天EC发送给BBOSS的文件数大于999,则从000重新开始

* 文件大小不能超过5M

XML 格式定义:

序号

父元素名称

元素名称

约束

类型

长度

描述

取值说明

1

InterBOSS

UserInfo

1

用户信息

1.1

UserInfo

BizCode

1

String

V10

业务代码

1.2

UserInfo

ProdName

?

String

V256

业务名称

1.3

UserInfo

ServCode

1

String

V21

服务代码

1.4

UserInfo

UserData

+

签约关系、黑白名单信息

1.4.1

UserData

MobNum

1

String

F11

用户手机号码

1.4.2

UserData

OprCode

1

String

F2

操作代码

01-加入

02-退出

1.4.3

UserData

EfftT

?

String

F8

用户希望的生效时间

YYYYMMDD

我的代码:

-- 存储过程名为 TEST_ZYP

create or replace procedure TEST_ZYP(in_mdns in varchar,out_retval

out number) is

-- PL_SQL程序块由3部分组成 声明部分 执行部分异常处理

--声明部分由关键字DECLARE开始(这里为什么没有DECLARE?)

--如果在这里加上

DECLARE ,其实是错的,因为上面的

is 就相当于declare

--定义参数:参数名称

参数类型

l_errcode

number; --oracle中对int double float进行整合成number类型

l_errmessage

varchar2(1000); --varchar2 长度可变最大4000个字节

--l_id

number;

--变量意义:ID号

l_mobile

varchar(100); --varchar

长度不可变最大2000个字节

--变量意义:l_mobile 手机号

--l_name

varchar(100);

l_oprcode

varchar2(10); --变量意义:操作代码

f_obj

utl_file.file_type; --utl_file:

oracle内置包提供一系列的文件操作

--utl_file.file_type 文件类型

--l_line

varchar2(1000);

l_filename

varchar2(200); --变量意义:组装的文件名称

l_conn

UTL_TCP.connection; --变量意义:FTP上传的链接

--UTL_TCP:

Oracle 内置包 使用UTL_TCP包通过TCP/IP协议来访问Internet资源,

--包括大家最熟悉的HTTP协议,传输文件(FTP),甚至发送邮件(SMTP),

l_ecid

varchar(10);--ECID

本企业标识

l_maxnum

number;--每个文件记录的手机号最大个数(因为要求每个文件不能超过 5M)

l_recycle

number;--循环记录编号

l_filenum

number;--文件编号(因为有最大文件容量,所以要求每天的文件后缀按000-999顺序循环生成)

l_curdate

varchar(10);--处理时的日期YYYYMMDD

l_curdatetime

varchar(20);--处理时的日期时间

YYYYMMDDhhmmss

l_bizcode

varchar2(50);--业务代码

l_prodname

varchar2(50);--业务名称

l_servcode

varchar2(50);--服务代码

--CURSOR

声明游标(后续动作为打开提取数据关闭)

CURSOR c_sms_main IS select a.id,a.mobile,a.name

from wl_al_linkren a inner join WL_AL_OPERATOR_NUMSECTION b on

substr(a.mobile,0,3)=b.mdnsect

where b.operatorid=0 and a.ftpflag=0;

c_sms_row c_sms_main % ROWTYPE;

-- % ROWTYPE:复合类型。声明变量c_sms_row可以存放游标c_sms_main一整行

--执行部分由BEGIN开始

BEGIN

--变量赋值

l_ecid := '400097';

l_maxnum := 10000;

l_bizcode := 'MBJ0010801';

l_prodname := '国家农业部信息中心';

l_servcode :='1065795157';

l_recycle:=0; --循环记录编号,用来判断是否该结束当前文件(超过指定的l_maxnum),组装新文件了

l_filenum :=-1; --文件编号000-999

--判断in_mdns,如有数据,写成一个文件,并上传到服务器。

IF in_mdns IS NOT NULL THEN --如果in_mdns不为空

BEGIN

--处理

l_ecid := '400097';

END;

END IF;

--开始处理数据库中的数据

OPEN c_sms_main; --打开游标

LOOP --直到型循环(LOOP---- EXIT [WHEN 条件] ----END LOOP)

FETCH c_sms_main INTO c_sms_row;--循环开始读取记录

FETCH INTO

将游标内容读入c_sms_main%ROWTYPE类型变量中

EXIT WHEN c_sms_main%NOTFOUND;--循环到达最后退出

%NOTFOUND 为游标4属性之一

---*************开始正儿八经的存储过程的逻辑编码**********-----

--根据ID更新数据库ftpflag状态

update wl_al_linkren set ftpflag=1 where

id=c_sms_row.id;

l_recycle := l_recycle+1;--计数器加1

IF 1=MOD(l_recycle,l_maxnum) THEN --计数器对l_maxnum取余为1

BEGIN

IF l_recycle>1 THEN --计数器大于1并且对l_maxnum取余为1,代表着一个文件已经满了

BEGIN

--把刚写满的这个文件结尾

utl_file.put(f_obj,'');

utl_file.put(f_obj,'');

--关闭文件

utl_file.fclose(f_obj);

--把这个文件上传

l_conn := ftp.login('192.168.88.54', '21', 'administrator',

'830528');

ftp.binary(p_conn => l_conn);

ftp.put(p_conn

=> l_conn,

p_from_dir

=> 'FTPDIR',

p_from_file => l_filename,

p_to_file

=> l_filename);

ftp.logout(l_conn);

END;

END IF;

--需要弄一个新文件

--新文件名组装

l_curdatetime := TO_CHAR(SYSDATE(),'YYYYMMDDHHMMSS');

l_filename :=l_ecid||'_OrdSub_';

l_filename :=l_filename||l_curdatetime||'_BBOSS.';

l_filenum := l_filenum+1;

IF

l_filenum=1000 THEN

BEGIN

l_filenum:=0;

END;

END IF;

l_filename :=l_filename||l_filenum;

--打开这个新文件

f_obj:=utl_file.fopen('FTPDIR',l_filename,'w');

--给新文件写head

utl_file.put(f_obj,'');

utl_file.put(f_obj,'');

utl_file.put(f_obj,''||l_bizcode||'');

utl_file.put(f_obj,''||l_prodname||'');

utl_file.put(f_obj,''||l_servcode||'');

END;

END IF;

--若不用创建新文件,就直接往f_obj中写数据

--utl_file.put_line(f_obj,l_line);

put_line:输出一行和一个行终止符

utl_file.put(f_obj,'');--put

:在当前行输出不包含终止符

utl_file.new_line(f_obj);--new_line:不指定行数时默认为1,既换行

--MobNum 用户手机号

l_mobile:=c_sms_row.mobile;

utl_file.put(f_obj,''||l_mobile||'');

utl_file.new_line(f_obj);

--OprCode

操作代码

l_oprcode := '01';

utl_file.put(f_obj,''||l_oprcode||'');

utl_file.new_line(f_obj);

--EfftT

用户希望的生效时间

l_curdate := TO_CHAR(SYSDATE(),'YYYYMMDD');

utl_file.put(f_obj,''||l_curdate||'');

utl_file.new_line(f_obj);

utl_file.put(f_obj,'');

END LOOP;

--如有记录,关闭文件对象并上传该文件

IF (l_recycle > 0) AND

(MOD(l_recycle,l_maxnum)>0) THEN

BEGIN

--做结尾

utl_file.put(f_obj,'');

utl_file.put(f_obj,'');

--关闭文件

utl_file.fclose(f_obj);

--上传文件

--连接FTP服务器上传文件到指定目录。

l_conn := ftp.login('192.168.88.54', '21', 'administrator',

'830528');

ftp.binary(p_conn

=> l_conn);

ftp.put(p_conn

=> l_conn,

p_from_dir

=> 'FTPDIR',

p_from_file => l_filename,

p_to_file

=> l_filename);

ftp.logout(l_conn);

END;

END IF;

utl_tcp.close_all_connections;

--结束,关闭游标

CLOSE c_sms_main;

------**********结束该存储过程的逻辑编码*************----

commit;--提交提交数据(这里是释放锁不是锁表),在未提交前你前面的操作更新的都是内存,没有更新到物理文件中。

out_retval := 0; --给输出赋值

--异常处理部分由EXCEPTION开始

exception

when others then

rollback;

l_errcode

:= sqlcode;

l_errmessage := sqlerrm;

insert into wl_al_exec_proc_log(id,

procname,

instime,

err_number,

err_message)

values

(seq_wl_al_exec_proc_log.nextval,

'proc_cms_ftp_lxr',

sysdate,

l_errcode,

l_errmessage);

commit;

out_retval := -1;

-- 由end结束存储过程

END TEST_ZYP;

编译过程中遇到的问题:

Q:以下代码报错,

IF in_mdns IS NOT NULL THEN --如果in_mdns不为空

BEGIN

END;

END IF;

A:这其实是想写这么个判断的流程,有这么个意思,并没有加具体做法。但是正是因为没有加具体做法,所以这个语法就错了。在C中可以这样写如下这一个空的if语句:

if(NULL!=in_mdns){} --正确,表示一个空的if语句

但是在Oracle中是不行的,因此,随便加个什么语句就好啦~

IF in_mdns IS NOT NULL THEN

BEGIN

--l_temp number; --错误,参数声明必须在declear中

l_ecid := '400097'; --正确

END;

END IF;

Q:以下代码报错:

utl_file.put(f_obj,"");

A: 在C中,字符用单引号;字符串用双引号。

在Oracle中,都是用单引号。

因此,改一下就好啦~

正确:

utl_file.put(f_obj,'');

Q:以下代码报错:

IF in_mdns IS NOT NULL THEN

BEGIN

l_ecid := '400097';

END

END IF

A:错心大意的我忘记在END后面加分号作为if/begin的结束了....

IF in_mdns IS NOT NULL THEN

BEGIN

l_ecid := '400097';

END;

END IF;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值