SQL server函数转Oracle问题之一,强行使用临时表

此文转载自:https://blog.csdn.net/qq_40791652/article/details/112213180#commentBox

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 ; 的方法调用

   

更多内容详见微信公众号:Python测试和开发

Python测试和开发

原文地址:https://www.cnblogs.com/phyger/p/14247146.html