SQL server函数转Oracle问题之一,强行使用临时表
(多次修改,现在可以用了)
1.工作中遇见的问题,背景是客户的数据库迁移,SQL server迁到Oracle。网上没有对应的办法,也不知对不对,至少不报BUG了,分享给大家
这种创建方法百度“Oracle函数返回结果集(或临时表)”有一堆,不重复说了。
注意:
临时表函数中还要定义,格式如下:
(就像JAVA的定义)
然后剩余步骤:
*****************分割线
*****************分割线
*****************分割线
*****************分割线
*****************分割线
sqlserver源码:
CREATE function [dbo].[fn_g_CompareAllData](@pk_corp varchar(20),@BeginDate datetime,@EndDate datetime)
returns @tem table
(
SN bigint,
--csalereceiveid char(20), --发货单主键
vreceivecode char(30), --发货单号
nnumber decimal(20,0), --数量
ntotaloutinvnum decimal(20,0), --数量
ntotaltransnum decimal(20,0), --累计运输数量
--csaleid char(20), --发货单主键
--pk_transport_h char(20), --运输单主键
vbillcode_t char(30), --运输单号
ntotalnumber decimal(20,0), --存货总数量
reserve5 decimal(20,0), --周转桶数
--transportcode char(20), --运输单主键
vbillcode_r char(30), --回收单号
ntotalnumber2 numeric(28,0), --发货单数量
backwaternum numeric(28,0), --退水数量
exwaternum numeric(28,0), --换水数量
yabucketnum numeric(28,0), --押退桶数量
getbucketnum numeric(28,0), --借/还桶数量
sendbucketnum numeric(28,0), --赠桶数量
backbucketnum numeric(28,0), --回桶数量
notclearnum numeric(28,0) --车辆未结清数量
)
begin
--set @pk_corp = '3001'
--set @BeginDate = '2013-08-01'
--set @EndDate = '2013-08-11'
set @pk_corp = (select top 1 pk_corp from bd_corp where unitcode = @pk_corp);
declare @All table
(
SN bigint identity(1,1),
csalereceiveid char(20), --发货单主键
vreceivecode char(30), --发货单号
nnumber decimal(20,0), --数量
ntotaloutinvnum decimal(20,0), --数量
ntotaltransnum decimal(20,0), --累计运输数量
csaleid char(20), --发货单主键
pk_transport_h char(20), --运输单主键
vbillcode_t char(30), --运输单号
ntotalnumber decimal(20,0), --存货总数量
reserve5 decimal(20,0), --周转桶数
transportcode char(20), --运输单主键
vbillcode_r char(30), --回收单号
ntotalnumber2 numeric(28,0), --发货单数量
backwaternum numeric(28,0), --退水数量
exwaternum numeric(28,0), --换水数量
yabucketnum numeric(28,0), --押退桶数量
getbucketnum numeric(28,0), --借/还桶数量
sendbucketnum numeric(28,0), --赠桶数量
backbucketnum numeric(28,0), --回桶数量
notclearnum numeric(28,0) --车辆未结清数量
);
with so_salereceive_w as
(
select
b.csalereceiveid,
b.vreceivecode,
sum(c.nnumber) as nnumber,
sum(c.ntotaloutinvnum) as ntotaloutinvnum,
sum(c.ntotaltransnum) as ntotaltransnum
from so_salereceive b with(nolock)
inner join so_salereceive_b c with(nolock) on b.csalereceiveid = c.csalereceiveid
inner join bd_invbasdoc d with(nolock) on c.cinvbasdocid = d.pk_invbasdoc
inner join bd_invcl e with(nolock) on d.pk_invcl = e.pk_invcl
where e.invclassname = '产成品'
and b.pk_corp = @pk_corp
and b.dapprovedate between @BeginDate and @EndDate
and IsNull(b.dr,0) = 0
group by b.csalereceiveid,b.vreceivecode
),
transport_w as
(
select
a.csaleid,
a.pk_transport_h,
b.vbillcode,
sum(a.ntotalnumber) as ntotalnumber,
sum(a.reserve5) as reserve5
from lbs_transport_b a with(nolock)
inner join lbs_transport_h b with(nolock) on a.pk_transport_h = b.pk_transport_h
inner join so_salereceive_w c with(nolock) on c.csalereceiveid = a.csaleid
where IsNull(b.dr,0) = 0
group by a.csaleid,a.pk_transport_h,b.vbillcode
),
tempReceipt_w as
(
select distinct
b.pk_receivebill_h,b.transportcode,b.vbillcode
from lbs_receivebill_h b with(nolock)
inner join transport_w c with(nolock) on c.pk_transport_h = b.transportcode
where IsNull(b.dr,0) = 0
),
Receive_w as
(
select
b.transportcode,
b.vbillcode,
sum(a.ntotalnumber) as ntotalnumber, --发货单数量
sum(backwaternum) as backwaternum, --退水数量
sum(exwaternum) as exwaternum, --换水数量
sum(yabucketnum) as yabucketnum, --押退桶数量
sum(getbucketnum) as getbucketnum, --借/还桶数量
sum(sendbucketnum) as sendbucketnum, --赠桶数量
sum(backbucketnum) as backbucketnum, --回桶数量
sum(notclearnum) as notclearnum --车辆未结清数量
from lbs_receivebill_b a with(nolock)
inner join tempReceipt_w b with(nolock) on a.pk_receivebill_h = b.pk_receivebill_h
group by b.transportcode,b.vbillcode
)
insert @All
(
--发货单
--csalereceiveid, --发货单主键
vreceivecode,
nnumber, --数量
ntotaloutinvnum, --数量
ntotaltransnum, --累计运输数量
--运输单
--csaleid, --发货单主键
--pk_transport_h , --运输单主键
vbillcode_t,
ntotalnumber, --存货总数量
reserve5, --周转桶数
--回桶单
--transportcode, --运输单主键
vbillcode_r,
ntotalnumber2, --发货单数量
backwaternum, --退水数量
exwaternum, --换水数量
yabucketnum, --押退桶数量
getbucketnum, --借/还桶数量
sendbucketnum, --赠桶数量
backbucketnum, --回桶数量
notclearnum --车辆未结清数量
)
select
a.vreceivecode,
a.nnumber, --数量
a.ntotaloutinvnum, --数量
a.ntotaltransnum,
-----------------------
b.vbillcode,
b.ntotalnumber, --存货总数量
b.reserve5, --周转桶数
-----------------------
c.vbillcode,
c.ntotalnumber, --发货单数量
c.backwaternum, --退水数量
c.exwaternum, --换水数量
c.yabucketnum, --押退桶数量
c.getbucketnum, --借/还桶数量
c.sendbucketnum, --赠桶数量
c.backbucketnum, --回桶数量
c.notclearnum
from so_salereceive_w a with(nolock)
left join transport_w b with(nolock) on a.csalereceiveid = b.csaleid
left join Receive_w c with(nolock) on b.pk_transport_h = c.transportcode
order by a.csalereceiveid,b.pk_transport_h,c.transportcode
;
update @All set nnumber = null,ntotaloutinvnum = null,ntotaltransnum = null
from @All ta
where SN <> (select min(SN) from @All where csalereceiveid = ta.csalereceiveid)
;
update @All set ntotalnumber = null,reserve5 = null
from @All ta
where SN <> (select min(SN) from @All where pk_transport_h = ta.pk_transport_h and csaleid = ta.csaleid)
;
insert @tem
(
SN,
--发货单
--csalereceiveid, --发货单主键
vreceivecode , --发货单号
nnumber, --数量
ntotaloutinvnum, --数量
ntotaltransnum, --累计运输数量
--运输单
--csaleid, --发货单主键
--pk_transport_h , --运输单主键
vbillcode_t,
ntotalnumber, --存货总数量
reserve5, --周转桶数
--回桶单
--transportcode, --运输单主键
vbillcode_r,
ntotalnumber2, --发货单数量
backwaternum, --退水数量
exwaternum, --换水数量
yabucketnum, --押退桶数量
getbucketnum, --借/还桶数量
sendbucketnum, --赠桶数量
backbucketnum, --回桶数量
notclearnum --车辆未结清数量
)
select
SN,
--发货单
--csalereceiveid, --发货单主键
vreceivecode , --发货单号
nnumber, --数量
ntotaloutinvnum, --数量
ntotaltransnum, --累计运输数量
--运输单
--csaleid, --发货单主键
--pk_transport_h , --运输单主键
vbillcode_t,
ntotalnumber, --存货总数量
reserve5, --周转桶数
--回桶单
--transportcode, --运输单主键
vbillcode_r,
ntotalnumber2, --发货单数量
backwaternum, --退水数量
exwaternum, --换水数量
yabucketnum, --押退桶数量
getbucketnum, --借/还桶数量
sendbucketnum, --赠桶数量
backbucketnum, --回桶数量
notclearnum --车辆未结清数量
from @All
order by SN;
return;
end
转化后的Oracle:
3, fn_g_CompareAllData --√
Oracler :
create sequence fn_g_Compare_sq maxvalue 99999999999999999999
increment by 1
start with 1;
--步长为1
create or replace type all_obj_type as object(
SN number(20), --发货单主键
csalereceiveid varchar2(20), --发货单主键
vreceivecode varchar2 (30), --发货单号
nnumber number (20,0), --数量
ntotaloutinvnum number (20,0), --数量
ntotaltransnum number (20,0), --累计运输数量
csaleid varchar2 (20), --发货单主键
pk_transport_h number (20), --运输单主键
vbillcode_t number (30), --运输单号
ntotalnumber number (20,0), --存货总数量
reserve5 number (20,0), --周转桶数
transportcode varchar2 (20), --运输单主键
vbillcode_r varchar2 (30), --回收单号
ntotalnumber2 number (28,0), --发货单数量
backwaternum number(28,0), --退水数量
exwaternum number (28,0), --换水数量
yabucketnum number (28,0), --押退桶数量
getbucketnum number (28,0), --借/还桶数量
sendbucketnum number (28,0), --赠桶数量
backbucketnum number (28,0), --回桶数量
notclearnum number (28,0) --车辆未结清数量
);
CREATE OR REPLACE TYPE all_tab_type IS TABLE OF all_obj_type;
create or replace type tem_obj_type as object(
SN number,
--csalereceiveid char(20), --发货单主键
vreceivecode varchar2 (30), --发货单号
nnumber number (20,0), --数量
ntotaloutinvnum number (20,0), --数量
ntotaltransnum number (20,0), --累计运输数量
vbillcode_t varchar2 (30), --运输单号
ntotalnumber number (20,0), --存货总数量
reserve5 number (20,0), --周转桶数
vbillcode_r varchar2 (30), --回收单号
ntotalnumber2 number (28,0), --发货单数量
backwaternum number (28,0), --退水数量
exwaternum number (28,0), --换水数量
yabucketnum number (28,0), --押退桶数量
getbucketnum number (28,0), --借/还桶数量
sendbucketnum number (28,0), --赠桶数量
backbucketnum number (28,0), --回桶数量
notclearnum number (28,0) --车辆未结清数量
);
CREATE OR REPLACE TYPE tem_tab_type IS TABLE OF tem_obj_type;
--定义工具类表,之后清除里面的数据
create table all_tab_linshi(
SN number(20),
csalereceiveid varchar2(20),
vreceivecode varchar2 (30),
nnumber number (20,0),
ntotaloutinvnum number (20,0),
ntotaltransnum number (20,0),
csaleid varchar2 (20),
pk_transport_h number (20),
vbillcode_t number (30),
ntotalnumber number (20,0),
reserve5 number (20,0),
transportcode varchar2 (20),
vbillcode_r varchar2 (30),
ntotalnumber2 number (28,0),
backwaternum number(28,0),
exwaternum number (28,0),
yabucketnum number (28,0),
getbucketnum number (28,0),
sendbucketnum number (28,0),
backbucketnum number (28,0),
notclearnum number (28,0)
);
Create table tem_tab_linshi(
SN number,
vreceivecode varchar2 (30), --发货单号
nnumber number (20,0), --数量
ntotaloutinvnum number (20,0), --数量
ntotaltransnum number (20,0), --累计运输数量
vbillcode_t varchar2 (30), --运输单号
ntotalnumber number (20,0), --存货总数量
reserve5 number (20,0), --周转桶数
vbillcode_r varchar2 (30), --回收单号
ntotalnumber2 number (28,0), --发货单数量
backwaternum number (28,0), --退水数量
exwaternum number (28,0), --换水数量
yabucketnum number (28,0), --押退桶数量
getbucketnum number (28,0), --借/还桶数量
sendbucketnum number (28,0), --赠桶数量
backbucketnum number (28,0), --回桶数量
notclearnum number (28,0)
);
--序列预备的函数
create or replace function get_fn_g_Compare_sq
return number
is
seq_val number ;
begin
execute immediate 'select fn_g_Compare_sq. NEXTVAL from dual' into seq_val ;
return seq_val ;
end get_fn_g_Compare_sq;
--函数本体
CREATE OR REPLACE function fn_g_CompareAllData(pk_corp_dec in varchar2,BeginDate_dec in date,EndDate_dec in date)
return tem_tab_type
IS
tab_tem tem_tab_type:= tem_tab_type();
v_pk_corp varchar2(20);
begin
select pk_corp into v_pk_corp
from(
select pk_corp
from bd_corp
where unitcode = pk_corp_dec) where rownum=1;
--这是分割线
insert into all_tab_linshi
(
Sn,
vreceivecode,
nnumber, --数量
ntotaloutinvnum, --数量
ntotaltransnum, --累计运输数量
vbillcode_t,
ntotalnumber, --存货总数量
reserve5, --周转桶数
vbillcode_r,
ntotalnumber2, --发货单数量
backwaternum, --退水数量
exwaternum, --换水数量
yabucketnum, --押退桶数量
getbucketnum, --借/还桶数量
sendbucketnum, --赠桶数量
backbucketnum, --回桶数量
notclearnum --车辆未结清数量
)
with so_salereceive_w as
(
select
b.csalereceiveid,
b.vreceivecode,
sum(c.nnumber) as nnumber,
sum(c.ntotaloutinvnum) as ntotaloutinvnum,
sum(c.ntotaltransnum) as ntotaltransnum
from so_salereceive b
inner join so_salereceive_b c on b.csalereceiveid = c.csalereceiveid
inner join bd_invbasdoc d on c.cinvbasdocid = d.pk_invbasdoc
inner join bd_invcl e on d.pk_invcl = e.pk_invcl
where e.invclassname = '产成品'
and b.pk_corp = v_pk_corp
and b.dapprovedate between BeginDate_dec and EndDate_dec
and nvl(b.dr,0) = 0
group by b.csalereceiveid,b.vreceivecode),
transport_w as
(
select
a.csaleid,
a.pk_transport_h,
b.vbillcode,
sum(a.ntotalnumber) as ntotalnumber,
sum(a.reserve5) as reserve5
from lbs_transport_b a
inner join lbs_transport_h b on a.pk_transport_h = b.pk_transport_h
inner join so_salereceive_w c on c.csalereceiveid = a.csaleid
where nvl(b.dr,0) = 0
group by a.csaleid,a.pk_transport_h,b.vbillcode
),
tempReceipt_w as
(
select distinct
b.pk_receivebill_h,b.transportcode,b.vbillcode
from lbs_receivebill_h b
inner join transport_w c on c.pk_transport_h = b.transportcode
where nvl(b.dr,0) = 0
),
Receive_w as
(
select
b.transportcode,
b.vbillcode,
sum(a.ntotalnumber) as ntotalnumber, --发货单数量
sum(backwaternum) as backwaternum, --退水数量
sum(exwaternum) as exwaternum, --换水数量
sum(yabucketnum) as yabucketnum, --押退桶数量
sum(getbucketnum) as getbucketnum, --借/还桶数量
sum(sendbucketnum) as sendbucketnum, --赠桶数量
sum(backbucketnum) as backbucketnum, --回桶数量
sum(notclearnum) as notclearnum --车辆未结清数量
from lbs_receivebill_b a
inner join tempReceipt_w b on a.pk_receivebill_h = b.pk_receivebill_h
group by b.transportcode,b.vbillcode)
Select
get_fn_g_Compare_sq,
a.vreceivecode,
a.nnumber, --数量
a.ntotaloutinvnum, --数量
a.ntotaltransnum,
-----------------------
b.vbillcode,
b.ntotalnumber, --存货总数量
b.reserve5, --周转桶数
-----------------------
c.vbillcode,
c.ntotalnumber, --发货单数量
c.backwaternum, --退水数量
c.exwaternum, --换水数量
c.yabucketnum, --押退桶数量
c.getbucketnum, --借/还桶数量
c.sendbucketnum, --赠桶数量
c.backbucketnum, --回桶数量
c.notclearnum
from so_salereceive_w a
left join transport_w b on a.csalereceiveid = b.csaleid
left join Receive_w c on b.pk_transport_h = c.transportcode
order by a.csalereceiveid,b.pk_transport_h,c.transportcode
;
update all_tab_linshi set nnumber = null,ntotaloutinvnum = null,ntotaltransnum = null
where SN != (select min(SN) from all_tab_linshi);
update all_tab_linshi set ntotalnumber = null,reserve5 = null
where SN != (select min(SN) from all_tab_linshi);
insert into tem_tab_linshi
(
SN,
vreceivecode , --发货单号
nnumber, --数量
ntotaloutinvnum, --数量
ntotaltransnum, --累计运输数量
vbillcode_t,
ntotalnumber, --存货总数量
reserve5, --周转桶数
vbillcode_r,
ntotalnumber2, --发货单数量
backwaternum, --退水数量
exwaternum, --换水数量
yabucketnum, --押退桶数量
getbucketnum, --借/还桶数量
sendbucketnum, --赠桶数量
backbucketnum, --回桶数量
notclearnum --车辆未结清数量
)
select
SN,
vreceivecode , --发货单号
nnumber, --数量
ntotaloutinvnum, --数量
ntotaltransnum, --累计运输数量
vbillcode_t,
ntotalnumber, --存货总数量
reserve5, --周转桶数
vbillcode_r,
ntotalnumber2, --发货单数量
backwaternum, --退水数量
exwaternum, --换水数量
yabucketnum, --押退桶数量
getbucketnum, --借/还桶数量
sendbucketnum, --赠桶数量
backbucketnum, --回桶数量
notclearnum --车辆未结清数量
from all_tab_linshi
order by SN;
--将临时表数据插入函数中的自定义表,
--然后情况临时表数据,返回自定义表
for i in
(SELECT Sn,vreceivecode,nnumber,ntotaloutinvnum,ntotaltransnum,
vbillcode_t,ntotalnumber,reserve5,vbillcode_r,ntotalnumber2,
backwaternum,exwaternum,yabucketnum,getbucketnum,sendbucketnum,
backbucketnum,notclearnum
FROM tem_tab_linshi)
loop
tab_tem.extend;
tab_tem (tab_tem.count) := tem_obj_type (i.Sn,i.vreceivecode,i.nnumber,i.ntotaloutinvnum,i.ntotaltransnum,
i.vbillcode_t,i.ntotalnumber,i.reserve5,i.vbillcode_r,
i.ntotalnumber2,i.backwaternum,i.exwaternum,i.yabucketnum,
i.getbucketnum,i.sendbucketnum,i.backbucketnum,i.notclearnum
);
end loop;
execute immediate
' truncate table tem_tab_linshi ';
execute immediate
' truncate table all_tab_linshi ';
return tab_tem;
end ;
有点随意,希望能给遇见同样问题的朋友帮助,可以私信我,不过新手很菜,只能帮一些。
(网上也有很多人不建议这种方法,如果想返回结果集,最好使用游标。但我还不熟悉游标,也恳请看到的大神给我建议)
然而这样的函数不报错,但使用 select 函数名(形参。。。) from dual 调用时却报查询或者DML中不允许执行DDL。。。。。。这方法不行
----分割线
PRAGMA AUTONOMOUS_TRANSACTION;
上面那一句,加在函数或者存储过程的第一个BEGIN之前,然后每一个函数或存储过程中的DML后面添加一个 commit;
如下面两个代码:
PRAGMA AUTONOMOUS_TRANSACTION;
begin
execute immediate
' delete so_salereceive_linshi ';
Commit;
execute immediate
' delete temReceipt_linshi ';
Commit;
execute immediate
' delete temReceipt2_linshi ';
Commit;
原理大概是Oracle中函数或者存储过程不允许DDL,DML的话要提交,PRAGMA AUTONOMOUS_TRANSACTION; 这句语句声明函数或存储过程为自治事务,然后使用delete 表名代替 truncate table 表名。
改后之后的函数可以用下面语句调用测试:
select 函数名(形参,形参。。。) from dual ; 的方法调用