oracle存儲過程遷移到PostgreSQL之問題總結


       首先通過了解,在oracle中寫的存儲過程很多都是在包里面,然而PostgreSQL沒有包的存在,我只能把每個包的存儲過程通過腳本轉化成PostgreSQL的函數;在PostgreSQL中的函數能滿足oracle中存儲過程的各種寫法實現。

       在處理過程中總結了一些不同之處的對比:

 

Oracle PostgreSql 說明
VARCHAR2 varchar  
DATE timestamp  
SYSDATE localtimestamp,now()  
clob text  
blob bytea  
number smallint/integer/bigint/numeric/real/double precision  
不支持boolean,可通過0/1代替 支持 boolean  
'==null ' != null  
a'||null == 'a' a'||null == null  
trunc(時間) date_trunc(text,time/timestamp/timestamptz)  
to_char to_char(待轉換值,轉換格式)  
to_number to_number(待轉換值,轉換格式)  
to_date to_date(待轉換值,轉換格式)  
decode case when或if判斷  
nvl coalesce()  
外連接(+) left(right) join  
goto語句 不支持  
%FOUND found 游標屬性
%NOTFOUND not found
%ISOPEN 不支持
%ROWCOUNT 不支持
  cursor名是全局的;所以用隱式聲明定義cursor,或者保證所有的程序中cursor名唯一  
COMMIT,ROLLBACK;SAVEPOINT 函數中不支持  
DBMS_OUTPUT,DBMS_SQL,UTIL_FILE,UTIL_MAIL包 不支持  
dual 不支持  
不支持 ::類型轉換  
  子查詢必須指定別名  
分頁rownum 分頁limit(limit必須用於 order by 之后)  
alter table tab_name add constraint pk_tab_name primary key(column_id) using index; alter table tab_name add constraint pk_tab_name primary key(column_id); 限制
create sequence SEQ_TAB_NAME
minvalue 1
maxvalue 9999999999999999
start with 1 increment by 1
cache 20;
create sequence seq_tab_name
minvalue 1
maxvalue 9223372036854775807
start 1
increment 1
cache 20;
Sequence語法及使用差異
select seq_tab_name.nextval from dual; select next_val(seq_tab_name);
wm_concat arrary_agg ()、 string_agg( )、 xmlagg() 分別來處理數組,字符串和xml文檔  

下面是在處理存儲過程移植過程中記錄下的對比情況:

oracle在存儲過程或者函數等中調用另外的函數或存儲過程賦值:comm_pkg.proc_cfg_validate(v_f_userid, v_f_tenantid, errcode, errmsg);或mTable := fun_gettablename(v_TenantID, 'bill_main'); 在pgsql函數中調用另外函數:
1.out返回數據的函數
out返回的數據名稱與into到變量的名稱相同時,不能直接into,可以取別名后再into
(1)可以這樣簡單粗暴的方式按照返回數據順序進行賦值
SELECT * INTO errcode,errmsg FROM seeyon_zzyw."COMM_PKG.PROC_CFG_VALIDATE"(v_UserID::numeric, v_TenantID);
(2)可以把返回數據列出進行賦值
SELECT errcode as f_code,errmsg as f_msg INTO errcode,errmsg FROM seeyon_zzyw."COMM_PKG.PROC_CFG_VALIDATE"(v_UserID::numeric, v_TenantID);
2.不是out返回數據的函數,是直接return返回的函數,需要考慮返回空值
(1)select coalesce((SELECT fun_gettablename from seeyon_zzyw.fun_gettablename(0, 'bill_main')),'') into mBillTableName from dual;
(2)SELECT seeyon_zzyw.fun_comm_isoperation(v_F_tenantID) into mcount;--這樣賦值,如果返回值是空會報錯
(3)mcount = fun_comm_auth(V_F_Userid);--這樣賦值,函數需要考慮是否為空
 
for cur in循環cur不需要聲明 pgsql 中需要進行聲明才行,可以聲明是游標或者記錄集  
to_date 帶時分秒用這個to_timestamp  
for cur_deleterole in (select r.f_Roleid,r.rolecode
from Sys_Role r
start with r.f_Roleid = V_F_ROLEID
connect by Prior r.f_Roleid = r.f_Parentid) loop
mid:= 'id=' || cur_deleterole.f_roleid || 'code='||cur_deleterole.rolecode;
dbms_output.put_line(mid);--控制台打印
end loop;
for mrole,mcode in (WITH RECURSIVE a AS (
SELECT r.f_Roleid,r.f_rolecode
FROM Sys_Role r
WHERE r.f_Roleid = V_F_ROLEID
UNION ALL
SELECT d.f_Roleid,d.f_rolecode
FROM Sys_Role d
JOIN a ON a.f_Roleid = d.f_Parentid )
SELECT f_Roleid,f_rolecode FROM a) loop
mid:= 'id=' || mrole || 'code='||mcode;
raise info '%',mid;--控制台打印
end loop;
1.oracle中start with connect by 語句在pgsql中換成with recursive 語句;2.oracle中for的值是結果集,而pgsql中是分別的字段並且for這些字段不能加括號。
執行動態SQL賦值游標: open unbound_refcursor for mysql open unbound_refcursor for execute mysql 重點關注,在pgsql中使用動態SQL拼接時,特別需要注意變量是否為null,如果是null需要自行轉化一下,因為在pgsql中null與字符串拼接的結果是null。
RAISE_APPLICATION_ERROR(-20001, '該單據已使用,不能刪除'); RAISE EXCEPTION '該單據已使用,不能刪除' USING ERRCODE = -20001;  
type up_drtemp_data is record(
f_a varchar(500),
f_b varchar(500),
f_c varchar(500),
f_d varchar(500),
f_e varchar(500),
f_f varchar(500),
f_g varchar(500),
f_h varchar(500),
f_i varchar(500),
f_j varchar(500),
f_k varchar(500),
f_l varchar(500),
f_m varchar(500),
f_n varchar(500)
);在函數或者包中直接聲明使用type
create type up_drtemp_data AS(
f_a varchar(500),
f_b varchar(500),
f_c varchar(500),
f_d varchar(500),
f_e varchar(500),
f_f varchar(500),
f_g varchar(500),
f_h varchar(500),
f_i varchar(500),
f_j varchar(500),
f_k varchar(500),
f_l varchar(500),
f_m varchar(500),
f_n varchar(500)
);在pgsql函數中要使用type需要另外創建,然后在函數中直接使用
 
創建自增系列ID方式:testseq_id_seq.nextval nextval('testseq_id_seq')  
open一個相同游標可以多次 只能open一次相同的游標  
trunc函數傳入數字是可以進行取整 trunc函數可以進行取整,但不支持時間操作,需要用date_trunc函數(需要傳轉換格式)  
在update, insert語句可以給表取別名 (1)這種支持給更新表取別名: update base_ItemStd_284 t set (f_aircomid,f_paytypeid,f_std,f_useBegin,
f_useend) = (select trunc(f_aircomid),
trunc(f_paytypeid),f_std,f_useBegin,
f_useend from base_itemstd_tmp bit
where f_guid='b4e00167-7134-89f6-dd23-05fbe3bb97c1'
and t.f_itemstdid = bit.f_itemstdid)
where exists(select f_itemstdid from base_itemstd_tmp bit
where t.f_itemstdid = bit.f_itemstdid
and f_guid='b4e00167-7134-89f6-dd23-05fbe3bb97c1'); (2)這種方式就不支持(不支持的可以用表名): update base_ItemStd_284 set (f_aircomid,f_paytypeid,f_std,f_useBegin,
f_useend) = (1,2,3,4,5)
where f_itemstdid=1
 
打印動態SQL等語句dbms_output.put_line(sqlText) pg中是raise info '%',sqlText;  
oracle中動態SQL可以直接拼接在執行函數或語句后面:open r_iplist for 'select count(*)
from base_handler a left outer join sys_user b
on a.f_userid = b.f_userid
and a.f_tenantid = '||trunc(r_tenantid)||'
and a.f_type not in (1, 2)'
pg中也可以,但是推薦在執行前先拼接完整賦值給變量如msql,再去執行:sqlText:='select count(*)
from base_handler a left outer join sys_user b
on a.f_userid = b.f_userid
and a.f_tenantid = '||trunc(r_tenantid)||'
and a.f_type not in (1, 2)'; open r_iplist for execute sqlText;
 
substr下標從0開始 substr下標從1開始  
substring(index1,index2) substring(字符串 from 開始索引 for 截取長度)  
sysdate>date1+datenum now()>(date1+(datenum || 'day')::interval)  
to_date可以轉化時分秒 to_date只能轉化到年月日,需要時分秒使用to_timestamp  
oracle中不同類型進行比較,賦值,where條件值,函數參數等等,會自動轉化類型 pgsql中類型不會進行自動轉化,所以要嚴格進行類型相同比較,賦值,函數參數等等  
execute immediate sqlText execute sqlText  
GROUPING_ID分組統計函數 不支持GROUPING_ID函數,可以使用grouping函數替換  
可以直接用rownum pgsql中需要使用函數row_number() over() as rownum  
oracle中表連接 select u.f_Userid,
u.f_Usercode,
u.f_Username,
decode(nvl(r.f_Roleid, 0), 0, 0, 1) as F_IsChecked,
r.f_Roleid,
u.f_Isdelete
from Sys_User u,
(select * from Sys_Roleuser where F_ROLEID = '722') r
where u.f_Userid = r.f_Userid(+)
and u.f_Tenantid = 284
and u.f_State = 1
and u.f_Isdelete = 0
order by u.f_Tenantid, u.f_Userid;
pgsql中表連接 select u.f_Userid,
u.f_Usercode,
u.f_Username,
decode(nvl(r.f_Roleid, 0), 0, 0, 1) as F_IsChecked,
r.f_Roleid,
u.f_Isdelete
from (select * from Sys_User where f_Tenantid=284
and f_State = 1
and f_isdelete = 0) u left outer join
(select * from Sys_Roleuser where F_ROLEID = '722') r
on u.f_Userid = r.f_Userid
--and u.f_Tenantid = 284
--and u.f_State = 1
--and u.f_isdelete = 0
order by u.f_Tenantid, u.f_Userid;
 
 
oracle支持這種天與時沒有空格轉化成時間to_date('2022-03-0412:11:41','YYYY-MM-DD hh24:mi:ss') pgsql不支持這種天與時沒有空格的to_timestamp('2022-03-0412:11:41','YYYY-MM-DD hh24:mi:ss')  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM