數據庫從PostgreSQL遷移至Oracle指導書(三)


前言:近日,公司的一套使用 postgresql 數據庫的應用軟件要兼容oracle。本文系統性地整理了PostgreSQL 和 Oracle的一些差異點,和應用程序中的改動點。

 

4    應用程序的改造

4.1 JDBC 配置

下面是PostgreSQL和Oracle的JDBC配置差異:

 

 

PostgreSQL 11

Oracle 19c

driver_class

org.postgresql.Driver

oracle.jdbc.driver.OracleDriver

url

jdbc:postgresql://127.0.0.1:5432/postgres

jdbc:oracle:thin:@127.0.0.1:1521:ORCL

 

4.2 常用函數和運算符

下面是PostgreSQL和Oracle中,對應的常用的數據庫函數和運算符:

 

 

PostgreSQL 11

Oracle 19c

類型轉換

value :: type

CAST(value AS type)

CAST(value AS type)

序列取值

nextval('sequence_name')

sequence_name.nextval

獲取uuid

gen_random_uuid() 或者uuid_generate_v1mc()

sys_guid()

模糊匹配且不區分大小寫

select * from tb_usergroup where group_name ilike 'group%'

select * from tb_usergroup where upper(group_name) like upper('group%');

時間加減

select now() - INTERVAL '3 months';

select now() - INTERVAL '3' month

select now() - INTERVAL '3' month from dual;

獲取當前時間

獲取事務開始時間戳:

select now();

select current_timestamp;

 

獲取當前命令執行的時間戳:

select clock_timestamp();

獲取事務開始時間戳:

 

獲取當前命令執行的時間戳:

select current_timestamp from dual;

獲取會話當前時刻UTC毫秒數

select extract(epoch from now()) * 1000;

select (CAST(SYS_EXTRACT_UTC(current_timestamp) AS date) - to_date('1970-01-01', 'YYYY-MM-DD')) * 86400*1000  + mod(extract(second from current_timestamp), 1) * 1000  from dual;

獲取會話當前時區的名稱

select current_setting('timezone');

select SESSIONTIMEZONE FROM DUAL;

獲取會話當前時區的偏移量(格式:+08:00)

select left(to_char(now(),'OF') || ':00', 6);

SELECT TZ_OFFSET(SESSIONTIMEZONE) FROM DUAL;

字符串聚集

select string_agg(name, ',') from man;

select listagg(name, ',') from man;

計算一個子串在字符串中出現的第一個位置

select strpos('abcd','c');

select instr('abcd','c') from dual;

正則表達式匹配

select 1 where  'abcd' ~ '^[a-z]*$';

select 1 from dual where regexp_like('abcd', '^[a-z]*$');

 

4.3 一些 sql 語法

下面是一些應用程序中需要改造的語法,這里列舉的都是DML語句。

 

 

PostgreSQL 11

Oracle 19c

查詢表之外的數據

select 1;

 

select 1 from dual;

 

注意:from dual 是固定的語法。

分頁查詢

select * FROM tablename offset m  limit n 

 select * FROM tablename  limit n offset m

select * from (SELECT rownum rn, tablename.* FROM tablename where ROWNUM <= m+n) where rn > m;

NULL和''

NULL和''不同

ORACLE認為''等同於NULL

批量插入

insert into tb01 (id) values(1),(2),(3);

insert into tb01 (id) values(1);

insert into tb01 (id) values(2);

insert into tb01 (id) values(3);

集合的減

except

minus

 

注意:分頁查詢中,m 表示起始位置,最小值為0,n 代表所取的行數。

4.4 JSON 功能

目前 iSecure Center (以下簡稱ISC)平台的基線版本使用了一些PostgreSQL (PostgreSQL 11)的NO-SQL 特性,包括數組和json。Oracle同樣提供了JSON和數組的處理功能。

下面是一些json功能的改造。

4.4.1 JSON 字段的類型

PostgreSQL 有原生類型json和jsonb。它們接受相同的輸入格式。它們實際的主要差別是效率。json 數據類型存儲輸入的文本內容,處理函數在處理時必須將它解析為JSON;而jsonb數據以分解的二進制格式存儲,這使得它由於添加了轉換機制而在輸入上稍微慢些,但是在處理上明顯更快,因為不需要重新解析。jsonb支持索引,這是一個明顯的優勢。        實際應用中,我們使用jsonb類型。

Oracle中,JSON字段用varchar或clob類型表示。在創建了這樣的字段后,需要用一個檢查約束確保數據是真正的json格式的。

下面是在 PostgreSQL 中創建一個包含jsonb類型的表的示例:

      

create table tb_test

(

            id int,

            json_column jsonb,

);

insert into tb_test (id, json_column) values (1, '{"name":"zhangsan","gender":"male","age":22}');

 

下面是在 Oracle 中創建一個包含json字段的表的示例:

create table tb_test

(

        id int,

         json_column clob,

       CHECK (json_column IS JSON)

);

insert into tb_test (id, json_column) values (1, '{"name":"zhangsan","gender":"male","age":22}');

4.4.2 JSON 的查詢

如果你要查詢JSON 中的值,則需要給出JSON 鍵的名稱或鍵的完整路徑。注意,對於JSON對象{"a":{"b":{"c": "foo"}}},在PostgreSQL 中JSON鍵路徑的表示為 {a,b,c};而在Oracle中,表示為 $.a.b.c

下面是兩種數據庫中,常用的json查詢功能的對比:

 

 

PostgreSQL 11

Oracle 19c

判斷JSON的最外層是否包含某個鍵

{"a":1, "b":2}'::jsonb ? 'a'

json_exists('{"a":1, "b":2}', '$.a')

給定一個鍵,它的值是普通文本

{"a":"1",  "b":{"c": "foo"}}' ->> 'a'

 

結果:

1

json_value('{"a":"1",  "b":{"c": "foo"}}' , '$.a')

 

結果:

1

給定一個鍵,它的值是一個json對象或json數組

’{"a":"1",  "b":{"c": "foo"}}‘ -> 'b'  (返回值的類型是jsonb/json)

 

結果:{"c": "foo"}

 

 

'{"a":"1",  "b":{"c": "foo"}}' ->> 'b' (返回值的類型是text)

 

結果:{"c": "foo"}

json_query('{"a":"1",  "b":{"c": "foo"}}' , '$.b')

 

結果:{"c": "foo"}

給定一個鍵的路徑,它的值是普通文本

{"a":"1",  "b":{"c": "foo"}}' #>> ‘{b, c}’

 

結果:foo

json_value('{"a":"1",  "b":{"c": "foo"}}' , '$.b.c')

給定一個鍵的路徑,它的值是 json 對象或json數組格式

{"a":"1", "b":{"c": "foo"}, "d":{"e":{"f":"1"}}}' #> ‘{d, e}’

(返回值的類型是jsonb/json)

 

結果:{"f":"1"}

 

 

{"a":"1", "b":{"c": "foo"}, "d":{"e":{"f":"1"}}}' #>> ‘{d, e}’

(返回值的類型是text)

 

結果:{"f":"1"}

json_query('{"a":"1", "b":{"c": "foo"}, "d":{"e":{"f":"1"}}}', '$.d.e')

 

結果:{"f":"1"}

取 json 數組中的第一個元素,

注意數組的下標從0開始

 '{"a":[1,2,3,4]}'::jsonb #>> '{a,0}'

json_value('{"a":[1,2,3,4]}','$.a[0]')

 

4.4.3 JSON 的修改

下面是兩種數據庫中,添加,修改和刪除JSON 鍵值對的方法:

 

 

PostgreSQL 11

Oracle 19c

合並或插入json 鍵值對

{"a":"1"}'::jsonb || '{"b":"1"}'::jsonb

 

結果:{"a":"1", "b" :"1"}

JSON_MERGEPATCH('{"a":"1"}',  '{"b":"1"}')

 

結果:{"a":"1", "b" :"1"}

刪除json 最外層的鍵值對

{"a":1, "b":2}'::jsonb - 'b'

 

結果:{"a":"1"}

 JSON_MERGEPATCH('{"a":"1", "b" :"1"}', '{"b":null}')

 

結果:{"a":"1"}

修改json 最外層鍵值對

{"a":"1", "b":"2"}'::jsonb || '{"b":"1"}'::jsonb

 

結果:{"a":"1", "b" :"1"}

JSON_MERGEPATCH('{"a":"1", "b":"2"}',  '{"b":"1"}')

 

結果:{"a":"1", "b" :"1"}

根據鍵的路徑在JSON中插入或修改值

jsonb_set('{"a":1,"b":{"c":"1"}}', '{b,c}','"2"', false)

 

結果:

{"a": 1, "b": {"c": "2"}}

JSON_MERGEPATCH('{"a":1,"b":{"c":"1"}}', '{"b":{"c":"2"}}')

 

結果:

{"a": 1, "b": {"c": "2"}}

 

4.4.4 JSON的比較

下面的是兩種數據庫中比較json的方法,返回結果是布爾類型:

 

 

PostgreSQL 11

Oracle 19c

比較json是否相等

 '{"a":"1"}' :: jsonb = '{"a":"1"}'::jsonb

json_equal('{"a":"1"}', '{"a":"1"}')

左邊的json 是否包含右邊的json

{"a":1, "b":2}'::jsonb @> '{"a":1}'::jsonb

json_equal(JSON_MERGEPATCH('{"a":"1", "b" :"1"}', '{"a":"1"}'), '{"a":"1", "b" :"1"}')

 

4.4.5 其他JSON 功能

下面是一些常用其他的JSON函數:

 

 

PostgreSQL 11

Oracle 19c

備注

創建一個json對象

jsonb_build_object('a',‘1’,'b',‘2’)

 

結果: {"a": "1", "b": "2"}

json_object(key 'a' value '1', key 'b' value '2')

 

結果: {"a": "1", "b": "2"}

 

把一個json中的鍵變成列

select * from jsonb_populate_record(null::myrowtype, '{"a":1,"b":2}')

 

結果:

a | b

---+---

 1 | 2

SELECT * FROM json_table('{"a":1, b:"2"}', '$' columns (a PATH '$.a', b PATH '$.b'))

 

結果:

a | b

---+---

 1 | 2

可以看出,Oracle中把json鍵轉成列,需要指定列名和json的鍵。

把一個含有json數組中的json對象的鍵變成列

select * from jsonb_populate_recordset(null::myrowtype, '[{"a":1,"b":2},{"a":3,"b":4}]')

 

結果:

a | b

---+---

 1 | 2

 3 | 4

SELECT * FROM json_table('[{"a":1,"b":2},{"a":3,"b":4}]', '$[*]' columns (a PATH '$.a', b PATH '$.b'))

 

結果:

a | b

---+---

 1 | 2

 3 | 4

可以看出,Oracle中把json鍵轉成列,需要指定列名和json的鍵。

將兩列多行數據聚集為一個json對象

select jsonb_object_agg(name, id)

from tb_man;

 

結果:

{"Tom":1,"Bob":2}

select json_objectagg(key name value id)

from tb_man;

 

結果:

{"Tom":1,"Bob":2}

 

 

4.5 數組功能

PostgreSQL 中提供了兩種的數組可作為字段類型,一種是數組類型,一種是類型是jsonb的json數組。而Oracle則只支持JSON數組。

現在我們介紹這兩種數據庫中數組的知識和對應的函數和運算符。

4.5.1 數組的類型

PostgreSQL 支持的數組有兩種,一種是數組類型,一種是json數組。

下面的案例是創建一張表,它的字段類型是整型數組類型:

create table tb_test

(

    id int,

    codes integer [],

);

insert into tb_test (id, codes) values (1, '{1, 2, 3, 4}');

insert into tb_test (id, codes) values (2, array[1, 2, 3, 4]);

 

下面的案例是創建一張表,它的字段類型是jsonb,格式是json數組:

create table tb_test

(

    id int,

    codes jsonb

);

insert into tb_test (id, codes) values (1,'[1, 2, 3, 4]');

 

而Oracle中,json數組的類型是varchar。創建包含數組字段的表的示例如下:

create table tb_test

(

    id int,

    codes  varchar(512),

    CHECK (attribute  IS JSON)

);

insert into tb_test (id, json_column) values (1, '[1, 2, 3, 4]');

4.5.2 數組的查詢

下面是兩種數據庫中,常見的涉及數組的查詢功能:

 

 

PostgreSQL 11

Oracle 19c

數組的類型

array 類型的數組

json 數組,類型為jsonb

json 數組,類型為varchar

判斷數組是否包含某個元素

array[1,2,3,4] @> array[1]

cast('[1, 2, 3, 4]' as jsonb) @> cast('[1]' as jsonb)

json_exists('[1, 2, 3]','$?(@ == "1")')

取數組中的第一個元素

 select (array[1,2,3,4])[1];

 

注意,數組下標從1開始,[1] 表示第1個元素

 select '[1,2,3,4]'::jsonb #>> '{0}'

 

注意,數組下標從0開始

SELECT  json_value('[1,2,3,4]','$[0]') from dual

 

注意,數組下標從0開始

 

4.5.3 數組的修改

下面是兩種數據庫中,常見的修改數組的方法:

 

 

 

PostgreSQL 11

Oracle 19c

數組的類型

array 類型的數組

json 數組,類型為jsonb

json 數組,類型為varchar

向數組末端追加一個元素

array_append(array[1,2], 3)

array[1,2] || array[3]

cast( '[1, 2]' as jsonb) || cast( '[3]' as jsonb)

 substr('[1, 2]', 1, length('[1, 2]') - 1) || '3]'

合並兩個數組

array[1,2] || array[3, 4]

array_cat(array[1,2], array[3,4])

cast( '[1, 2]' as jsonb) || cast( '[3, 4]' as jsonb)

substr('[1, 2]', 1, length('[1, 2]') - 1) || '3, 4]'

從數組中刪除值為2的數字元素

array_remove(ARRAY[1,2,3,2], 2)

 

結果:

{1,3}

不支持,實現復雜

不支持,實現復雜

從數組中刪除值為“b”的字符串元素

array_remove(ARRAY['a ', 'b', 'c'], 'b')

 

結果:

['a', 'c ']

Cast('["a", "b", "c"]' as jsonb) -'b'

 

結果:

['a', 'c ']

不支持,實現復雜

  

4.5.4 數組的比較 

下面是兩種數據庫中,常見的數組的比較方法:

 

 

PostgreSQL 11

Oracle 19c

數組的類型

array 類型的數組

json 數組,類型為jsonb

json 數組,類型為varchar

比較數組是否相等

array[1,2,3,4] = array[1,2,3]

cast('[1, 2, 3, 4]' as jsonb) = cast('[1,2,3]' as jsonb)

json_equal('[1, 2, 3, 4]', '[1,2,3]')

判斷左邊的數組是否包含右邊的數組

array[1,2,3,4] @> array[1,2]

cast('[1, 2, 3, 4]' as jsonb) @> cast('[1,2]' as jsonb)

不支持直接比較數組,需要把右邊的數組拆分:

json_exists('[1, 2, 3]','$?(@ == "1")') and json_exists('[1, 2, 3]','$?(@ == "2")')

 

4.5.5 其他數組功能

下面是一些常用其他的數組功能:

 

 

PostgreSQL 11

Oracle 19c

數組的類型

array 類型的數組

json 數組,類型為jsonb

json 數組,類型為varchar

計算數組的元素個數

select array_length(array[1,2,3], 1)

select jsonb_array_length('[1, 2, 3, 4]')

SELECT count(*) FROM json_table('[1, 2, 3]', '$[*]' COLUMNS (value PATH '$'))

將不同的行聚合成一個數組

select array_agg(code) from tb_device where device_type = 'super';

select jsonb_agg(code) from tb_device where device_type = 'super';

select json_arrayagg(code) from tb_device where device_type = 'super';

將數組元素轉成多個行

select unnest(array[1,2,3]);

select cast(jsonb_array_elements('[1,2,3]' as text);

SELECT value

FROM json_table( '[1, 2, 3]' , '$[*]' COLUMNS (value PATH '$') )

 

從上面的例子可以看出,PostgreSQL 11 對 數組的支持要比Oracle多。


免責聲明!

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



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