日本熟妇hd丰满老熟妇,中文字幕一区二区三区在线不卡 ,亚洲成片在线观看,免费女同在线一区二区

文檔

Oracle應用遷移至云原生數據倉庫 AnalyticDB PostgreSQL 版

更新時間:

AnalyticDB PostgreSQL對Oracle語法有著較好的兼容,本文介紹如何將Oracle應用遷移到AnalyticDB PostgreSQL

基于ora2pg完成初步轉換工作

可以使用開源工具ora2pg進行最初的Oracle應用轉換。您可以使用ora2pg將Oracle的表DDL,view,package等語法轉換成PostgreSQL兼容的語法。具體操作方法請參見ora2pg的用戶文檔。

說明

由于腳本轉換后的PostgreSQL語法版本比AnalyticDB PostgreSQL使用的PostgreSQL內核版本高,而且ora2pg依賴規則進行轉換,難免會存在偏差,因此您還需要手動對轉換后的SQL腳本做糾正。

Oracle兼容性

兼容性模式參數

因相同函數在不同數據庫中行為有差異、互相不兼容,需要通過兼容性模式參數進行區分配置,目前包括PostgreSQL、Oracle兩種模式。

AnalyticDB PostgreSQL版提供了如下參數控制兼容性模式。

參數名稱

說明

adb_compatibility_mode

兼容性模式,取值如下:

  • postgres(默認值):開啟PostgreSQL兼容性模式。

  • oracle:開啟Oracle兼容性模式。

配置參數之前建議先通過SHOW adb_compatibility_mode;查看當前參數的值。

如果要修改數據庫實例級別參數,請提交工單聯系技術支持進行修改。

字符串連接操作符的兼容性模式

對于字符串連接表達式'abc' || NULL,其中的'abc'NULL可以是常量,也可以是來自基表或計算結果的數據。

  • 在PostgreSQL模式下,表達式的返回值為NULL。在PostgreSQL中,與NULL的任何串聯都會產生NULL

  • 在Oracle模式下,表達式的返回值為'abc'。在Oracle中,NULL與空字符串''等價。

    重要

    使用Oracle兼容性下的字符串連接功能,需要關閉Laser(laser.enable = off)。

數據類型支持

AnalyticDB PostgreSQL版對常量字符串提供了數據類型支持,無需設置兼容性參數就可以提供支持。

CREATE TABLE AS SELECT等場景下,對于常量字符串可以自動識別為Text類型,而非unknown類型。

使用Orafce插件

AnalyticDB PostgreSQL中提供了Orafce插件,該插件提供了一些兼容Oracle的函數。對于這些函數,您無需任何修改轉換即可在AnalyticDB PostgreSQL中使用。

在使用Orafce插件前,請執行如下命令進行安裝。

CREATE EXTENSION orafce;

Orafce插件提供的兼容函數如下表所示。

表 1. Orafce插件兼容函數表

函數

描述

示例

nvl(anyelement, anyelement)

  • 若第一個參數為null,則會返回第二個參數。

  • 若第一個參數不為null,則返回第一個參數。

說明

兩個參數必須是相同類型。

  • SELECT nvl(null,1);

    返回信息如下:

    nvl
    -----
      1
    (1 row)
  • SELECT nvl(0,1);

    返回信息如下:

    nvl
    -----
      0
    (1 row)
  • SELECT nvl(0,null);

    返回信息如下:

    nvl
    -----
      0
    (1 row)

add_months(day date, value int)RETURNS date

在第一個月份參數上加上第二個月份參數,返回類型為date。

SELECT add_months(current_date, 2);

返回信息如下:

add_months
------------
2019-08-31
(1 row)

last_day(value date)

返回某年某個月份的最后一天,返回類型為date。

SELECT last_day('2018-06-01');

返回信息如下:

 last_day
------------
2018-06-30
(1 row)

next_day(value date, weekday text)

  • 參數一:開始的日期。

  • 參數二:包含星期幾的英文字符串,如Friday。

返回開始日期后的第二個星期幾的日期,如第二個Friday。

SELECT next_day(current_date, 'FRIDAY');

返回信息如下:

 next_day
------------
2019-07-05
(1 row)

next_day(value date, weekday integer)

  • 參數一:開始的日期。

  • 參數二:星期幾的數字,取值為1到7,1為星期日,2為星期一,以此類推。

返回開始日期加天數之后的日期。

  • SELECT next_day('2019-06-22', 1);

    返回信息如下:

     next_day
    ------------
    2019-06-23
    (1 row)
  • SELECT next_day('2019-06-22', 2);

    返回信息如下:

     next_day
    ------------
    2019-06-24
    (1 row)

months_between(date1 date, date2 date)

返回date1和date2之間的月數。

  • 如果date1晚于date2,結果為正。

  • 如果date1早于date2,結果為負。

  • SELECT months_between('2019-01-01', '2018-11-01');

    返回信息如下:

    months_between
    ----------------
                 2
    (1 row)
  • SELECT months_between('2018-11-01', '2019-01-01');

    返回信息如下:

    months_between
    ----------------
                -2
    (1 row)

trunc(value timestamp with time zone, fmt text)

  • 參數一:要被截斷的timestamp。

  • 參數二:應用于截斷的度量單位,如年,月,日,周,時,分,秒等。

    • Y:截斷成日期年份的第一天。

    • Q:返回季度的第一天。

  • SELECT TRUNC(current_date,'Q');

    返回信息如下:

      trunc
    ------------
    2019-04-01
    (1 row)
  • SELECT TRUNC(current_date,'Y');

    返回信息如下:

      trunc
    ------------
    2019-01-01
    (1 row)

trunc(value timestamp with time zone)

截斷timestamp,默認截斷時分秒。

SELECT TRUNC('2019-12-11'::timestamp);

返回信息如下:

        trunc
------------------------
2019-12-11 00:00:00+08
(1 row)

trunc(value date)

截斷日期。

SELECT TRUNC('2019-12-11'::timestamp,'Y');

返回信息如下:

        trunc
------------------------
2019-01-01 00:00:00+08

round(value timestamp with time zone, fmt text)

將timestamp圓整到最近的unit_of_measure(日,周等)。

SELECT round('2018-10-06 13:11:11'::timestamp, 'YEAR');

返回信息如下:

        round
------------------------
2019-01-01 00:00:00+08
(1 row)

round(value timestamp with time zone)

默認圓整到天。

SELECT round('2018-10-06 13:11:11'::timestamp);

返回信息如下:

        round
------------------------
2018-10-07 00:00:00+08
(1 row)

round(value date, fmt text)

參數類型為date。

  • SELECT round(TO_DATE('27-OCT-00','DD-MON-YY'), 'YEAR');

    返回信息如下:

      round
    ------------
    2001-01-01
    (1 row)
  • SELECT round(TO_DATE('27-FEB-00','DD-MON-YY'), 'YEAR');

    返回信息如下:

      round
    ------------
    2000-01-01
    (1 row)

round(value date)

參數類型為date。

SELECT round(TO_DATE('27-FEB-00','DD-MON-YY'));

返回信息如下:

  round
------------
2000-02-27
(1 row)

instr(str text, patt text, start int, nth int)

在一個string中搜索一個substring,若搜索到則返回substring在string中位置,若沒有搜索到,則返回0。

  • start:搜索的起始位置。

  • nth:搜索第幾次出現的位置。

  • SELECT instr('Greenplum', 'e',1,2);

    返回信息如下:

    instr
    -------
        4
    (1 row)
  • SELECT instr('Greenplum', 'e',1,1);

    返回信息如下:

    instr
    -------
        3
    (1 row)

instr(str text, patt text, start int)

未提供nth參數,默認是第一次出現的位置。

SELECT instr('Greenplum', 'e',1);

返回信息如下:

instr
-------
    3
(1 row)

instr(str text, patt text)

未提供start參數,默認從頭開始搜索。

SELECT instr('Greenplum', 'e');

返回信息如下:

instr
-------
    3
(1 row)

plvstr.rvrs(str text, start int, end int)

str為輸入的字符串start;end分別為對字符串從start到end這一段進行逆序。

SELECT plvstr.rvrs('adb4pg', 5,6);

返回信息如下:

reverse
---------
gp
(1 row)

plvstr.rvrs(str text, start int)

從start開始到字符串結束進行逆序。

SELECT plvstr.rvrs('adb4pg', 4);

返回信息如下:

reverse
---------
gp4
(1 row)

plvstr.rvrs(str text)

逆序整個字符串。

SELECT plvstr.rvrs('adb4pg');

返回信息如下:

reverse
---------
gp4bda
(1 row)

concat(text, text)

將兩個字符串拼接在一起。

SELECT concat('adb','4pg');

返回信息如下:

concat
--------
adb4pg
(1 row)

concat(text, anyarray)/concat(anyarray, text)/concat(anyarray, anyarray)

用于拼接任意類型的數據。

  • SELECT concat('adb4pg', 6666);

    返回信息如下:

      concat
    ------------
    adb4pg6666
    (1 row)
  • SELECT concat(6666, 6666);

    返回信息如下:

     concat
    ----------
    66666666
    (1 row)
  • SELECT concat(current_date, 6666);

    返回信息如下:

        concat
    ----------------
    2019-06-306666
    (1 row)

nanvl(float4, float4)/nanvl(float4, float4)/nanvl(numeric, numeric)

如果第一個參數為數值類型,則返回第一個參數;如果不為數值類型,則返回第二參數。

  • SELECT nanvl('NaN', 1.1);

    返回信息如下:

    nanvl
    -------
      1.1
    (1 row)
  • SELECT nanvl('1.2', 1.1);

    返回信息如下:

    nanvl
    -------
      1.2
    (1 row)

bitand(bigint, bigint)

將兩個整型的二進制進行and操作,并返回and之后的結果,只輸出一行。

  • SELECT bitand(1,3);

    返回信息如下:

    bitand
    --------
         1
    (1 row)
  • SELECT bitand(2,6);

    返回信息如下:

    bitand
    --------
         2
    (1 row)
  • SELECT bitand(4,6);

    返回信息如下:

    bitand
    --------
         4
    (1 row)

listagg(text)

將文本值聚集成一個串。

SELECT listagg(t) FROM (VALUES('abc'), ('def')) as l(t);

返回信息如下:

listagg
---------
abcdef
(1 row)

listagg(text, text)

將文本值聚集成一個串,第二個參數執行了分割符。

SELECT listagg(t, '.') FROM (VALUES('abc'), ('def')) as l(t);

返回信息如下:

listagg
---------
abc.def
(1 row)

nvl2(anyelement, anyelement, anyelement)

如果第一個參數不為null,那么返回第二個參數,如果第一個參數為null,則返回第三個參數。

  • SELECT nvl2(null, 1, 2);

    返回信息如下:

    nvl2
    ------
       2
    (1 row)
  • SELECT nvl2(0, 1, 2);

    返回信息如下:

    nvl2
    ------
       1
    (1 row)

lnnvl(bool)

如果參數為null或者false,則返回true;如果為true,則返回false。

  • SELECT lnnvl(null);

    返回信息如下:

    lnnvl
    -------
    t
    (1 row)
  • SELECT lnnvl(false);

    返回信息如下:

    lnnvl
    -------
    t
    (1 row)
  • SELECT lnnvl(true);

    返回信息如下:

    lnnvl
    -------
    f
    (1 row)

dump("any")

返回一個文本值,該文本中包含參數的數據類型代碼、以字節計的長度和內部表示。

SELECT  dump('adb4pg');

返回信息如下:

                dump
---------------------------------------
Typ=705 Len=7: 97,100,98,52,112,103,0
(1 row)

dump("any", integer)

參數二表示返回文本值的內部表示是使用10進制還是16進制,目前僅支持10進制和16進制。

  • SELECT dump('adb4pg', 10);

    返回信息如下:

                    dump
    ---------------------------------------
    Typ=705 Len=7: 97,100,98,52,112,103,0
    (1 row)
  • SELECT dump('adb4pg', 16);

    返回信息如下:

                   dump
    ------------------------------------
    Typ=705 Len=7: 61,64,62,34,70,67,0
    (1 row)
  • SELECT dump('adb4pg', 2);

    返回信息如下:

    ERROR:  unknown format (others.c:430)

nlssort(text, text)

指定排序規則的排序數據函數。

建表并插入數據:

CREATE TABLE t1 (name text);
INSERT INTO t1 VALUES('Anne'), ('anne'), ('Bob'), ('bob');
  • SELECT * FROM t1 ORDER BY nlssort(name, 'en_US.UTF-8');

    返回信息如下:

    name
    ------
    anne
    Anne
    bob
    Bob
    (4 row)
  • SELECT * FROM t1 ORDER BY nlssort(name, 'C');

    返回信息如下:

    name
    ------
    Anne
    Bob
    anne
    bob
    (4 row)

substr(str text, start int)

獲取參數一中字符串的子串。參數二表示獲取到子串的起始位置 >= start

  • SELECT substr('adb4pg', 1);

    返回信息如下:

    substr
    --------
    adb4pg
    (1 row)
  • SELECT substr('adb4pg', 4);

    返回信息如下:

    substr
    --------
    4pg
    (1 row)

substr(str text, start int, len int)

參數三會指定子串的結束位置 >= start and <= end

SELECT substr('adb4pg', 5,6);

返回信息如下:

substr
--------
pg
(1 row)

pg_catalog.substrb(varchar2, integer, integer)

varchar2類型的獲取子串函數。參數二為start pos,參數三為end pos。

SELECT  substr('adb4pg'::varchar2, 5,6);

返回信息如下:


substr
--------
pg
(1 row)

pg_catalog.substrb(varchar2, integer)

varchar2類型的獲取子串函數;參數二為start pos,從start pos一直取到字符串結束。

SELECT substr('adb4pg'::varchar2, 4) ;

返回信息如下:

substr
--------
4pg
(1 row)

pg_catalog.lengthb(varchar2)

獲取varchar2類型字符串占的字節數。若輸入為null返回null,輸入為空字符,則返回0。

  • SELECT lengthb('adb4pg'::varchar2) ;

    返回信息如下:

    lengthb
    ---------
          6
    (1 row)
  • SELECT lengthb('分析型'::varchar2) ;

    返回信息如下:

    lengthb
    ---------
          9
    (1 row)

lpad(string char, length int, fill char)

使用填充字符串將左填充到指定長度。

  • 參數一:字符串。

  • 參數二:指定長度。

  • 參數三:填充字符串fill。

說明

當字符串是CHAR 類型,PostgreSQL刪除尾隨空格,Oracle不刪除尾隨空格。

SELECT lpad('abc '::char(4),6,'x');

返回信息如下:

  lpad
--------
 xxabc
(1 row)

lpad(string char, length int)

使用空格將字符串左填充到指定長度。

SELECT lpad('abc '::char(4),6);

返回信息如下:

  lpad
--------
   abc
(1 row)

regexp_count(string text, pattern text, startPos int, flags text)

返回一個整數,表示從起始位置開始,模式串在源字符串出現的次數。 如果未找到模式串,則該函數返回0。

  • 參數一:源字符串。

  • 參數二:模式串。

  • 參數三:搜索起始位置,為正整數,不允許從源字符串末尾搜索負值。

  • 參數四:字符表達式,可更改函數的默認匹配行為,其可以包含以下一個或多個字符。

    • 'i':不區分大小寫的匹配。默認情況下,區分大小寫和重音。

    • 'c':區分大小寫和區分重音的匹配。

    • 'n':英文句點 (.) 與換行符匹配。 默認情況下,句點與換行符不匹配。

    • 'm':將源字符串視為多行。默認情況下,源字符串被視為單行。

    • 'x':忽略空白字符。 默認情況下,空白字符與其自身匹配。

  • SELECT regexp_count('a'||CHR(10)||'d', 'a.d', 1, 'n');

    返回信息如下:

     regexp_count 
    --------------
                1
    (1 row)
  • SELECT regexp_count('a'||CHR(10)||'d', 'a.d', 1, 'n');

    返回信息如下:

     regexp_count 
    --------------
                1
    (1 row)

regexp_count(string text, pattern text, startPos int)

返回一個整數,表示從起始位置開始,pattern在string出現的次數。 如果未找到pattern,則該函數返回0。

SELECT regexp_count('abc', '[a-z]',3);

返回信息如下:

 regexp_count
--------------
            1
(1 row)

regexp_count(string text, pattern text)

返回一個整數,表示從頭開始,pattern在string出現的次數。 如果未找到pattern,則該函數返回0。

SELECT regexp_count('abc', '[a-z]');

返回信息如下:

 regexp_count
--------------
            3
(1 row)

regexp_instr(string text, pattern text, startPos int, occurence int, return_opt int, flags text, group int)

返回一個整數,表示源字符串中模式匹配項所在的開始或結束位置。

  • 參數一:源字符串。

  • 參數二:模式串。

  • 參數三:搜索起始位置,為正整數,不允許從源字符串末尾搜索負值。

  • 參數四:出現次數,為正整數,指示應搜索源字符串中出現的模式串。 默認值為 1,表示模式串在源字符串中第一次出現。

  • 參數五:指示匹配模式串的開始或結束位置。

    • 0(默認值):返回出現的第一個字符的位置。

    • 1:返回出現后的字符的位置。

  • 參數六:字符表達式,可更改函數的默認匹配行為。更多信息,請參見REGEXP_COUNT

  • 參數七:捕獲組序號,對于帶有捕獲組的模式串,group為正整數,指示函數應返回模式串中對應序號的捕獲組。 捕獲組可以嵌套,它們按照左括號在模式串中出現的順序進行編號。 如果group為0,則返回與模式串匹配的整個子字符串的位置。 如果group值超過模式串中捕獲組的數量,則該函數返回0。默認值為0。

SELECT regexp_instr('abxxabc','(a)(b)(c)',1,1,0,'',2);

返回信息如下:

 regexp_instr
--------------
            6
(1 row)

regexp_instr(string text, pattern text, startPos int, occurence int, return_opt int, flags text)

返回一個整數,表示從起始位置開始,在string中pattern出現第occurence次的開始或結束位置。

  • return_opt:指示匹配模式串的開始或結束位置。

    • 0(默認值):返回出現的第一個字符的位置。

    • 1:返回出現后的字符的位置。

  • flags:可更改函數的默認匹配行為。更多信息,請參見REGEXP_COUNT

SELECT regexp_instr('abxxabc','(a)(b)(c)',1,1,0,'');

返回信息如下:

 regexp_instr
--------------
            5
(1 row)

regexp_instr(string text, pattern text, startPos int, occurence int, return_opt int)

返回一個整數,表示從起始位置開始,在string中pattern出現第occurence次的開始或結束位置。

return_opt:指示匹配模式串的開始或結束位置。

  • 0(默認值):返回出現的第一個字符的位置。

  • 1:返回出現后的字符的位置。

SELECT regexp_instr('abc','[a-z]{3}',1,1,1);

返回信息如下:

 regexp_instr
--------------
            4
(1 row)

regexp_instr(string text, pattern text, startPos int, occurence int)

返回一個整數,表示從起始位置開始,在string中pattern出現第occurence次的位置。

SELECT regexp_instr('abcd','[a-z]{2}',1,2);

返回信息如下:

 regexp_instr
--------------
            3
(1 row)

regexp_instr(string text, pattern text, startPos int)

返回一個整數,表示從起始位置開始,在string中pattern出現的位置。

SELECT regexp_instr('abc','[a-z]',2);

返回信息如下:

 regexp_instr
--------------
            2
(1 row)

regexp_instr(string text, pattern text)

返回一個整數,表示從頭開始,在string中pattern出現的位置。

SELECT regexp_instr('abc','[a-z]');

返回信息如下:

 regexp_instr
--------------
            1
(1 row)

regexp_like(string text, pattern text, flags text)

當模式串在源字符串中匹配時返回true,否則返回false。

  • 參數一:源字符串。

  • 參數二:模式串。

  • 參數三:字符表達式,可更改函數的默認匹配行為。更多信息,請參見REGEXP_COUNT

SELECT regexp_like('a'||CHR(10)||'d', 'a.d', 'n');

返回信息如下:

 regexp_like
-------------
 t
(1 row)

regexp_like(string text, pattern text)

當pattern在string中匹配時返回true,否則返回false。

SELECT regexp_like('abc', '[a-z]');

返回信息如下:

 regexp_like
-------------
 t
(1 row)

regexp_substr(string text, pattern text, startPos int, occurence int, flags text)

返回源字符串中與模式串匹配的子字符串。

  • 參數一:源字符串。

  • 參數二:模式串。

  • 參數三:搜索起始位置,為正整數,不允許從源字符串末尾搜索負值。

  • 參數四:出現次數occurence,為正整數,指示應搜索源字符串中出現的模式串。 默認值為1,表示模式串在源字符串中第一次出現。

  • 參數五:字符表達式,可更改函數的默認匹配行為。更多信息,請參見REGEXP_COUNT

SELECT regexp_substr('a,bc,def', '[^,]+',1,2,'');

返回信息如下:

 regexp_substr
---------------
 bc
(1 row)

regexp_substr(string text, pattern text, startPos int, occurence int)

返回從起始位置開始,在string中第occurence次與pattern匹配的子字符串。

SELECT regexp_substr('a,bc,def', '[^,]+',4,2);

返回信息如下:

 regexp_substr
---------------
 def
(1 row)

regexp_substr(string text, pattern text, startPos int)

返回從起始位置開始,在string中與pattern匹配的子字符串。

SELECT regexp_substr('a,bc,def', '[^,]+',4);

返回信息如下:

 regexp_substr
---------------
 c
(1 row)

regexp_substr(string text, pattern text)

返回從頭開始,在string中與pattern匹配的子字符串。

SELECT regexp_substr('a,bc,def', '[^,]+');

返回信息如下:

 regexp_substr
---------------
 a
(1 row)

Orafce插件除了提供上述兼容函數,還對Oracle的Varchar2數據類型提供了兼容。

對于以下的四個Oracle函數,在AnalyticDB PostgreSQL中,無需安裝Orafce插件就可以提供兼容支持。

函數

描述

示例

sinh(float)

雙曲正弦值。

SELECT sinh(0.1);

返回信息如下:

      sinh
-------------------
0.100166750019844
(1 row)

tanh(float)

雙曲正切值。

SELECT  tanh(3);

返回信息如下:

      tanh
------------------
0.99505475368673
(1 row)

cosh(float)

雙曲余弦值。

SELECT cosh(0.2);

返回信息如下:

      cosh
------------------
1.02006675561908
(1 row)

decode(expression, value, return [,value,return]... [, default])

在表達式中尋找一個搜索值,搜索到則返回指定的值。如果沒有搜索到,返回默認值。

創建表并插入數據:

CREATE TABLE t1(id int, name varchar(20));
INSERT INTO t1 values(1,'alibaba');
INSERT INTO t1 values(2,'adb4pg');
  • SELECT decode(id, 1, 'alibaba', 2, 'adb4pg', 'not found') from t1;

    返回信息如下:

     case
    ---------
    alibaba
    adb4pg
    (2 rows)
  • SELECT decode(id, 3, 'alibaba', 4, 'adb4pg', 'not found') from t1;

    返回信息如下:

      case
    -----------
    not found
    not found
    (2 rows)

數據類型轉換對照表

Oracle

AnalyticDB PostgreSQL

VARCHAR2

varchar or text

DATE

timestamp

LONG

text

LONG RAW

bytea

CLOB

text

NCLOB

text

BLOB

bytea

RAW

bytea

ROWID

oid

FLOAT

double precision

DEC

decimal

DECIMAL

decimal

DOUBLE PRECISION

double precision

INT

int

INTEGER

integer

REAL

real

SMALLINT

smallint

NUMBER

numeric

BINARY_FLOAT

double precision

BINARY_DOUBLE

double precision

TIMESTAMP

timestamp

XMLTYPE

xml

BINARY_INTEGER

integer

PLS_INTEGER

integer

TIMESTAMP WITH TIME ZONE

timestamp with time zone

TIMESTAMP WITH LOCAL TIME ZONE

timestamp with time zone

系統函數轉換對照表

Oracle

AnalyticDB PostgreSQL

sysdate

current timestamp

trunc

trunc或date trunc

dbms_output.put_line

raise語句

decode

轉成case when或直接使用decode

NVL

coalesce

PL/SQL遷移指導

PL/SQL(Procedural Language/SQL)是一種過程化的SQL語言,是Oracle對SQL語句的拓展。PL/SQL使得SQL的使用可以具有一般編程語言的特點,可以用來實現復雜的業務邏輯。PL/SQL對應了AnalyticDB PostgreSQL中的PL/PGSQL。

Package

PL/PGSQL不支持Package,需要把Package轉換成schema,同時Package里面的所有procedure和function也需要轉換成AnalyticDB PostgreSQL的function。

例如:

CREATE OR REPLACE PACKAGE pkg IS 

…

END;

轉換成:

CREATE SCHEMA pkg;
  • Package定義的變量

    Procedure/Function的局部變量保持不變,全局變量在AnalyticDB PostgreSQL中可以使用臨時表進行保存。

  • Package初始化塊

    請刪除,若無法刪除請使用Function封裝,在需要的時候主動調用該Function。

  • Package內定義的Procedure/Function

    Package內定義的Procedure和Function需要轉成AnalyticDB PostgreSQL的Function,并把Function定義到Package對應的Schema內。

    例如,有一個Package名為pkg中有如下函數:

    FUNCTION test_func (args int) RETURN int is
    var number := 10;
    BEGIN
    … …
    END;

    轉換成如下AnalyticDB PostgreSQL的Function:

    CREATE OR REPLACE FUNCTION pkg. test_func(args int) RETURNS int AS
    $$
    
      … …
    
    $$
     LANGUAGE plpgsql;

Procedure/Function

Oracle中的Procedure和Function,不論屬于Package的還是屬于全局,都需要轉換成AnalyticDB PostgreSQL的Function。

例如:

CREATE OR REPLACE FUNCTION test_func (v_name varchar2, v_version varchar2)
RETURN varchar2 IS
    ret varchar(32);
BEGIN
    IF v_version IS NULL THEN
        ret := v_name;
ELSE
    ret := v_name || '/' || v_version;
    END IF;
    RETURN ret;
END;

轉化成:

CREATE OR REPLACE FUNCTION test_func (v_name varchar, v_version varchar)
RETURNS varchar AS
$$

DECLARE
    ret varchar(32);
BEGIN
    IF v_version IS NULL THEN
        ret := v_name;
ELSE
    ret := v_name || '/' || v_version;
    END IF;
    RETURN ret;
END;

$$
 LANGUAGE plpgsql;

Procedure/Function轉換的注意事項有以下幾點:

  • RETURN關鍵字轉成RETURNS。

  • 函數體使用&dollar;\$ ... &dollar;\$進行封裝。

  • 函數語言聲明。

  • Subprocedure需要轉換成AnalyticDB PostgreSQL的Function。

PL statement

  • FOR語句:

    PL/SQL和PL/PGSQL在帶有REVERSE的整數FOR循環中的工作方式不同:

    • PL/SQL中是從第二個數向第一個數倒數。

    • PL/PGSQL是從第一個數向第二個數倒數。

    因此在移植時需要交換循環邊界,如下所示:

    FOR i IN REVERSE 1..3 LOOP
        DBMS_OUTPUT.PUT_LINE (TO_CHAR(i));
    END LOOP;

    轉換成:

    FOR i IN REVERSE 3..1 LOOP
        RAISE ‘%’ ,i;
    END LOOP;
  • PRAGMA語句

    AnalyticDB PostgreSQL中沒有PRAGMA語句,刪除該類語句。

  • 事務處理

    AnalyticDB PostgreSQL的Function內部無法使用事務控制語句,如begin,commit,rollback等。

    修改方法如下:

    • 刪除函數體內的事務控制語句,把事務控制放在函數體外。

    • 把函數按照commit或rollback拆分成多個。

  • EXECUTE語句

    AnalyticDB PostgreSQL支持類似Oracle的動態SQL語句,不同之處如下:

    • 不支持using語法,可通過把參數拼接到SQL串中來解決。

    • 數據庫標識符使用quote_ident包裹,數值使用quote_literal包裹。

    示例:

    EXECUTE 'UPDATE employees_temp SET commission_pct = :x' USING a_null;

    轉換成:

    EXECUTE 'UPDATE employees_temp SET commission_pct = ' || quote_literal(a_null);
  • Pipe row

    Pipe row函數,可使用AnalyticDB PostgreSQL的Table Function函數來替換。

    示例:

    TYPE pair IS RECORD(a int, b int);
    TYPE numset_t IS TABLE OF pair;
    
    FUNCTION f1(x int) RETURN numset_t PIPELINED IS
    DECLARE
        v_p pair;
    BEGIN
        FOR i IN 1..x LOOP
          v_p.a := i;
          v_p.b := i+10;
          PIPE ROW(v_p);
        END LOOP;
        RETURN;
    END;
    
    select * from f1(10);

    轉換成:

    CREATE TYPE pair AS (a int, b int);
    
    CREATE OR REPLACE FUNCTION f1(x int) RETURNS SETOF PAIR AS
    $$
    
    DECLARE
    REC PAIR;
    BEGIN
        FOR i IN 1..x loop
            REC := row(i, i+10);
            RETURN NEXT REC;
        END LOOP;
        RETURN ;
    END
    
    $$
     language 'plpgsql';
    
    SELECT * FROM f1(10);
  • 異常處理

    • 使用raise拋出異常。

    • Catch異常后,不能rollback事務,只能在udf外做rollback。

    • AnalyticDB PostgreSQL支持的Error,請參見PostgreSQL官網

  • Function中同時有Return和OUT參數

    AnalyticDB PostgreSQL中,Function無法同時存在return和out參數,需要把返回的參數改寫成out類型參數。

    示例:

    CREATE OR REPLACE FUNCTION test_func(id int, name varchar(10), out_id out int) returns varchar(10)
    AS $body$
    BEGIN
          out_id := id + 1;
          return name;
    end
    $body$
    LANGUAGE PLPGSQL;

    轉換成:

    CREATE OR REPLACE FUNCTION test_func(id int, name varchar(10), out_id out int, out_name out varchar(10))
    AS $body$
    BEGIN
          out_id := id + 1;
          out_name := name;
    end
    $body$
    LANGUAGE PLPGSQL;

    SELECT * FROM test_func(1,’1’) INTO rec;從rec中取對應字段的返回值即可。

  • 字符串連接中變量含有單引號

    在如下示例中,變量param2是一個字符串類型。假設param2的值為adb'-'pg。下面的sql_str直接放到AnalyticDB PostgreSQL中使用會將-識別成一個operator而報錯。需要使用quote_literal函數來進行轉換。

    示例:

    sql_str := 'SELECT * FROM test1 WHERE col1 = ' || param1 || ' AND col2 = '''|| param2 || '''AND col3 = 3';

    轉換成:

    sql_str := 'SELECT * FROM test1 WHERE col1 = ' || param1 || ' AND col2 = '|| quote_literal(param2) || 'AND col3 = 3';
  • 獲取兩個timestamp相減后的天數

    示例:

    SELECT to_date('2019-06-30 16:16:16') - to_date('2019-06-29 15:15:15') + 1 INTO v_days FROM dual;

    轉換成:

    SELECT extract('days' from '2019-06-30 16:16:16'::timestamp - '2019-06-29 15:15:15'::timestamp + '1 days'::interval)::int INTO v_days;

PL數據類型

  • Record

    使用AnalyticDB PostgreSQL的復合數據類型替換。

    示例:

    TYPE rec IS RECORD (a int, b int);

    轉換成:

    CREATE TYPE rec AS (a int, b int);
  • Nest table

    • Nest table作為PL變量,可以使用AnalyticDB PostgreSQL的array類型替換。

      示例:

      DECLARE
        TYPE Roster IS TABLE OF VARCHAR2(15);
        names Roster :=
        Roster('D Caruso', 'J Hamil', 'D Piro', 'R Singh');
      BEGIN
        FOR i IN names.FIRST .. names.LAST
        LOOP
            IF names(i) = 'J Hamil' THEN
              DBMS_OUTPUT.PUT_LINE(names(i));
            END IF;
        END LOOP;
      END;

      轉換成:

      CREATE OR REPLACE FUNCTION f1() RETURNS VOID AS
      $$
      
      DECLARE
          names varchar(15)[] := '{"D Caruso", "J Hamil", "D Piro", "R Singh"}';
          len int := array_length(names, 1);
      BEGIN
          for i in 1..len loop
              if names[i] = 'J Hamil' then
                  raise notice '%', names[i];
              end if;
          end loop;
          return ;
      END
      
      $$
       language 'plpgsql';
      
      SELECT f();
    • 作為Function返回值,可以使用Table Function替換。

  • Associative Array

    無替換類型。

  • Variable-Size Arrays

    與Nest table類似,使用array類型替換。

  • Global variables

    目前AnalyticDB PostgreSQL不支持Global variables,可以把Package中的所有Global variables存入一張臨時表(temporary table)中,然后修改定義,獲取Global variables的函數。

    示例:

    CREATE TEMPORARY TABLE global_variables (
            id int,
            g_count int,
            g_set_id varchar(50),
            g_err_code varchar(100)
    );
    
    INSERT INTO global_variables VALUES(0, 1, null,null);
    
    CREATE OR REPLACE FUNCTION get_variable() returns setof global_variables AS
    
    $$
    
    DECLARE
        rec global_variables%rowtype;
    BEGIN
        execute 'select * from global_variables' into rec;
        return next rec;
    END;
    
    $$
     LANGUAGE plpgsql;
    
    CREATE OR REPLACE FUNCTION set_variable(in param varchar(50), in value anyelement) returns void AS
    
    $$
    
    BEGIN
        execute 'update global_variables set ' ||  quote_ident(param) || ' = ' || quote_literal(value);
    END;
    
    $$
     LANGUAGE plpgsql;

    臨時表Global_variables中,字段ID為這個表的分布列,由于AnalyticDB PostgreSQL中不允許對于分布列的修改,需要加一個tmp_rec record;字段。

    修改一個全局變量時,使用:select * from set_variable(‘g_error_code’, ‘error’::varchar) into tmp_rec;

    獲取一個全局變量時,使用:select * from get_variable() into tmp_rec; error_code := tmp_rec.g_error_code;

SQL

  • Connect by

    Oracle層次查詢,AnalyticDB PostgreSQL沒有等價替換的SQL語句。可以使用循環按層次遍歷這樣的轉換思路。

    示例:

    CREATE TABLE employee(
           emp_id numeric(18),
           lead_id numeric(18),
           emp_name varchar(200),
           salary numeric(10,2),
           dept_no varchar(8)
    );
    INSERT INTO employee values('1',0,'king','1000000.00','001');
    INSERT INTO employee values('2',1,'jack','50500.00','002');
    INSERT INTO employee values('3',1,'arise','60000.00','003');
    INSERT INTO employee values('4',2,'scott','30000.00','002');
    INSERT INTO employee values('5',2,'tiger','25000.00','002');
    INSERT INTO employee values('6',3,'wudde','23000.00','003');
    INSERT INTO employee values('7',3,'joker','21000.00','003');
    INSERT INTO employee values('3',7,'joker','21000.00','003');
    SELECT emp_id,lead_id,emp_name,prior emp_name as lead_name,salary
         FROM employee
         START WITH  lead_id=0
         CONNECT BY prior emp_id =  lead_id

    轉換成:

    CREATE OR REPLACE FUNCTION f1(tablename text, lead_id int, nocycle boolean) RETURNS setof employee AS
    $$
    
    DECLARE
        idx int := 0;
        res_tbl varchar(265) := 'result_table';
        prev_tbl varchar(265) := 'tmp_prev';
        curr_tbl varchar(256) := 'tmp_curr';
    
        current_result_sql varchar(4000);
        tbl_count int;
    
        rec record;
    BEGIN
    
        execute 'truncate ' || prev_tbl;
        execute 'truncate ' || curr_tbl;
        execute 'truncate ' || res_tbl;
        loop
            -- 查詢當前層次結果,并插入到tmp_curr表
            current_result_sql := 'insert into ' || curr_tbl || ' select t1.* from ' || tablename || ' t1';
    
            if idx > 0 then
                current_result_sql := current_result_sql || ', ' || prev_tbl || ' t2 where t1.lead_id = t2.emp_id';
            else
                current_result_sql := current_result_sql || ' where t1.lead_id = ' || lead_id;
            end if;
            execute current_result_sql;
    
            -- 如果有環,刪除已經遍歷過的數據
            if nocycle is false then
                execute 'delete from ' || curr_tbl || ' where (lead_id, emp_id) in (select lead_id, emp_id from ' || res_tbl || ') ';
            end if;
    
            -- 如果沒有數據,則退出
            execute 'select count(*) from ' || curr_tbl into tbl_count;
            exit when tbl_count = 0;
    
            -- 把tmp_curr數據保存到result表
            execute 'insert into ' || res_tbl || ' select * from ' || curr_tbl;
            execute 'truncate ' || prev_tbl;
            execute 'insert into ' || prev_tbl || ' select * from ' || curr_tbl;
            execute 'truncate ' || curr_tbl;
            idx := idx + 1;
        end loop;
    
        -- 返回結果
        current_result_sql := 'select * from ' || res_tbl;
        for rec in execute current_result_sql loop
            return next rec;
        end loop;
        return;
    END
    
    $$
     language plpgsql;
  • Rownum

    1. 限定查詢結果集大小,可以使用limit替換。

      示例:

      SELECT * FROM t WHERE rownum < 10;

      轉換成:

      SELECT * FROM t LIMIT 10;
    2. 使用row_number() over()生成rownum。

      示例:

      SELECT rownum, * FROM t;

      轉換成:

      SELECT row_number() over() AS rownum, * FROM t;
  • Dual表

    1. 去掉Dual。

      示例:

      SELECT sysdate FROM dual;

      轉換成:

      SELECT current_timestamp;
    2. 創建一個叫dual的表。

  • Select中的udf

    AnalyticDB PostgreSQL支持在select中調用udf,但是udf中不能有SQL語句,否則會收到如下的錯誤信息:

    ERROR: function cannot execute on segment because it accesses relation "public.t2" (functions.c:155) (seg1 slice1 127.0.0.1:25433 pid=52153) (cdbdisp.c:1326)
    DETAIL:
    SQL statement "select b from t2 where a = $1 "

    可以把SELECT中的udf轉換成SQL表達式或者子查詢等方法來轉換。

    示例:

    CREATE OR REPLACE FUNCTION f1(arg int) RETURN int IS
        v int;
    BEGIN
        SELECT b INTO v FROM t2 WHERE a = arg;
        RETURN v;
    END;
    
    SELECT  a, f1(b) FROM t1;

    轉換成:

    SELECT t1.a, t2.b FROM t1, t2 WHERE t1.b = t2.a;
  • (+)多表外鏈接

    AnalyticDB PostgreSQL不支持(+)語法形式,需要轉換成標準的Outer Join語法。

    示例:

    SELECT * FROM a,b WHERE a.id=b.id(+)

    轉換成:

    SELECT * FROM a LEFT JOIN b ON a.id=b.id

    若在(+)中有三表的Join,需要先用WTE做兩表的Join,再用+號那個表跟WTE表做Outer Join。

    示例:

    SELECT * FROM test1 t1, test2 t2, test3 t3 WHERE t1.col1(+) BETWEEN NVL(t2.col1, t3.col1) ADN NVL(t3.col1, t2.col1);

    轉換成:

    WITH cte AS (SELECT t2.col1 AS low, t2.col2, t3.col1 AS high, t3.col2 AS c2 FROM t2, t3)
    SELECT * FROM t1 RIGHT OUTER JOIN cte ON t1.col1 BETWEEN coalesce(cte.low, cte.high) AND coalesce(cte.high,cte.low);
  • Merge Into

    通常情況下Merge Into語法可以通過INSERT ON CONFLICT語法進行適配,但是Merge Into語法的部分功能INSERT ON CONFLICT語法暫時無法實現,需要使用存儲過程解決。

    INSERT ON CONFLICT語法更多介紹,請參見使用INSERT ON CONFLICT覆蓋寫入數據

    存儲過程的更多介紹,請參見存儲過程

  • Sequence

    示例:

    CREATE SEQUENCE seq1;
    SELECT seq1.nextval FROM dual;

    轉換成:

    CREATE SEQUENCE seq1;
    SELECT nextval('seq1');
  • Cursor的使用

    • 在Oracle中,可以使用下面的語句對cursor進行遍歷。

      示例:

      FUNCTION test_func() IS
          Cursor data_cursor IS SELECT * from test1;
      BEGIN
          FOR I IN data_cursor LOOP
              Do something with I;
      END LOOP;
      END;

      轉換成:

      CREATE OR REPLACE FUNCTION test_func()
      AS $body$
      DECLARE
      data_cursor cursor for select * from test1;
      I record;
      BEGIN
          Open data_cursor;
          LOOP
             Fetch data_cursor INTO I;
            If not found then
                  Exit;
            End if;
            Do something with I;
          END LOOP;
          Close data_cursor;
      END;
      $body$
      LANGUAGE PLPGSQL;
    • Oracle可以在遞歸調用的函數里重復打開名字相同的cursor。但是在AnalyticDB PostgreSQL中則無法重發重復打開,需要改寫成for I in query的形式。

      示例:

      FUNCTION test_func(level IN numer) IS
          Cursor data_cursor IS SELECT * from test1;
      BEGIN
      If level > 5 then
              return;
         End if;
      
          FOR I IN data_cursor LOOP
              Do something with I;
              test_func(level + 1);
      END LOOP;
      END;

      轉換成:

      CREATE OR REPLACE FUNCTION test_func(level int) returns void
      AS $body$
      DECLARE
      data_cursor cursor for select * from test1;
      I record;
      BEGIN
          If level > 5 then
              return;
          End if;
          For I in select * from test1 LOOP
            Do something with I;
             PERFORM test_func(level+1);
          END LOOP;
      END;
      $body$
      LANGUAGE PLPGSQL;