2016-11-16 223 views
4

我想從表Tests_1解析CLOB列中的JSON字符串,並將其插入到另一個表(Test_2)中。我如何解析PL/SQL中的JSON字符串

如何在不使用任何JSON庫的情況下在PL/SQL中執行此操作?

取決於:

create table Tests_1 
(
    value CLOB 
) 
create table Test_2 (a date,b date,c number,d number, e number) 

INSERT INTO Tests_1 
    (value) 
VALUES 
    ('{ 
"a":"01/01/2015", 
"b":"31/12/2015", 
"c":"11111111111", 
"d":"1111111111", 
"e":"1234567890" 
}'); 
+0

什麼是你的Oracle版本? 12.1.0.2具有[原生JSON支持](https://docs.oracle.com/database/121/NEWFT/chapter12102.htm#NEWFT505)。 – user272735

+0

我的Oracle版本是11.0.4.1774 –

+1

11.0.4.1774不是Oracle RDBMS版本號。看起來像你正在使用的PL/SQL Developer版本,這在這裏不相關。 –

回答

2

甲骨文12C支持JSON

,如果你有一個現有的表根本就

ALTER TABLE table1 ADD CONSTRAINT constraint_name CHECK (your_column IS json); 
SELECT t.your_column.id FROM table1 t; 

請注意,由於某種原因t的暱稱是必要的

或完全例如:

CREATE TABLE json_documents (
    id RAW(16) NOT NULL, 
    data CLOB, 
    CONSTRAINT json_documents_pk PRIMARY KEY (id), 
    CONSTRAINT json_documents_json_chk CHECK (data IS JSON) 
); 

INSERT INTO json_documents (id, data) 
VALUES (SYS_GUID(), 
     '{ 
      "FirstName"  : "John", 
      "LastName"  : "Doe", 
      "Job"   : "Clerk", 
      "Address"  : { 
           "Street" : "99 My Street", 
           "City"  : "My City", 
           "Country" : "UK", 
           "Postcode" : "A12 34B" 
          }, 
      "ContactDetails" : { 
           "Email" : "[email protected]", 
           "Phone" : "44 123 123456", 
           "Twitter" : "@johndoe" 
          }, 
      "DateOfBirth" : "01-JAN-1980", 
      "Active"   : true 
     }'); 




SELECT a.data.FirstName, 
     a.data.LastName, 
     a.data.Address.Postcode AS Postcode, 
     a.data.ContactDetails.Email AS Email 
FROM json_documents a; 


FIRSTNAME  LASTNAME  POSTCODE EMAIL 
--------------- --------------- ---------- ------------------------- 
Jayne   Doe    A12 34B [email protected] 
John   Doe    A12 34B [email protected] 

2 rows selected. 

更多信息

+0

通過在Oracle 18c中引入'TREAT AS JSON',它將變得更簡單:) – lad2025

3

隨着 11.0.4版本(當然還有沒有11.0.4版) 你(從編寫解析器脫穎而出) 至少有兩個選擇RDBMS的版本使用的是,這裏有幾個選項:

第一個:爲Oracle 11.1.0.7及以上,安裝先端5和使用apex_json包:

-- here I have 12.1.0.1 version with version 5 of apex installed 

column ora_version format a21; 
column apex_version format a21; 


select (select version from v$instance) as ora_version 
    , (select version_no from apex_release) as apex_version 
    from dual; 

--drop table test_2; 
/* our test table */ 
create table test_2(
    c_a date, 
    c_b date, 
    c_c number, 
    c_d number, 
    c_e number 
); 

select * from test_2; 

declare 
    l_json_doc clob; 
begin 
    dbms_output.put_line('Parsing json...'); 
    l_json_doc := '{"a":"01/01/2015","b":"31/12/2015", 
        "c":"11111111111","d":"1111111111", 
        "e":"1234567890"}'; 
    apex_json.parse(l_json_doc); 
    insert into test_2(c_a, c_b, c_c, c_d, c_e) 
    values(apex_json.get_date(p_path=>'a', p_format=>'dd/mm/yyyy'), 
      apex_json.get_date(p_path=>'b', p_format=>'dd/mm/yyyy'), 
      to_number(apex_json.get_varchar2(p_path=>'c')), 
      to_number(apex_json.get_varchar2(p_path=>'d')), 
      to_number(apex_json.get_varchar2(p_path=>'e'))); 
    commit; 
    dbms_output.put_line('Done!'); 
end; 
/

column c_c format 99999999999; 
select to_char(c_a, 'dd/mm/yyyy') as c_a 
    , to_char(c_b, 'dd/mm/yyyy') as c_b 
    , c_c 
    , c_d 
    , c_e 
    from test_2; 

結果:

ORA_VERSION   APEX_VERSION   
--------------------- --------------------- 
12.1.0.1.0   5.0.2.00.07   

1 row selected. 

Table created. 

no rows selected. 

Parsing json... 
Done! 
PL/SQL procedure successfully completed. 


C_A  C_B     C_C  C_D  C_E 
---------- ---------- ------------ ---------- ---------- 
01/01/2015 31/12/2015 11111111111 1111111111 1234567890 

1 row selected. 

之一:使用開源PL/JSON。以前從未使用過,所以我藉此機會嘗試一下。這與apex_json非常相似。

declare 
    l_json  json; --json object 
    l_json_doc clob; 
begin 
    dbms_output.put_line('Parsing json...'); 

    -- parsing is done upon object instantiation 

    l_json_doc := '{"a":"01/01/2015","b":"31/12/2015", 
        "c":"11111111111","d":"1111111111", 
        "e":"1234567890"}'; 
    l_json := json(l_json_doc); 


    insert into test_2(c_a, c_b, c_c, c_d, c_e) 
    values(to_date(l_json.get('a').get_string, 'dd-mm-yyyy'), 
      to_date(l_json.get('b').get_string, 'dd-mm-yyyy'), 
      to_number(l_json.get('c').get_string), 
      to_number(l_json.get('d').get_string), 
      to_number(l_json.get('e').get_string)); 
    commit; 
    dbms_output.put_line('Done!'); 
end; 

column c_c format 99999999999; 
select to_char(c_a, 'dd/mm/yyyy') as c_a 
    , to_char(c_b, 'dd/mm/yyyy') as c_b 
    , c_c 
    , c_d 
    , c_e 
    from test_2; 

結果:json_table()在12.1.0.2版本

C_A  C_B     C_C  C_D  C_E 
---------- ---------- ------------ ---------- ---------- 
01/01/2015 31/12/2015 11111111111 1111111111 1234567890 
01/01/2015 31/12/2015 11111111111 1111111111 1234567890 

2 rows selected. 

介紹使得JSON解析有點簡單(只用於演示的緣故):

insert into test_2 
    select to_date(c_a, 'dd-mm-yyyy') 
     , to_date(c_b, 'dd-mm-yyyy') 
     , c_c 
     , c_d 
     , c_e 
    from json_table('{"a":"01/01/2015", 
         "b":"31/12/2015", 
         "c":"11111111111", 
         "d":"1111111111", 
         "e":"1234567890"}' 
        , '$' 
        columns ( 
         c_a varchar2(21) path '$.a', 
         c_b varchar2(21) path '$.b', 
         c_c varchar2(21) path '$.c', 
         c_d varchar2(21) path '$.d', 
         c_e varchar2(21) path '$.e' 
        )) ; 

結果:

select * 
    from test_2; 


C_A   C_B    C_C  C_D  C_E 
----------- ----------- ---------- ---------- ---------- 
1/1/2015 12/31/2015 1111111111 1111111111 1234567890 
4

因爲您指定了不想使用任何JSON庫,所以如果格式已修復,則可以將它強制轉換爲可解析爲XML的內容,從剝離花括號開始,用等號替換冒號,然後除去double - 從每個名稱/值對的第一部分開始的引號:

select regexp_replace(regexp_replace(value, '(^{|}$)'), 
    '^"(.*)":(".*")($|,)', '\1=\2', 1, 0, 'm') 
from tests_1; 

REGEXP_REPLACE(REGEXP_REPLACE(VALUE,'(^{|}$)'),'^"(.*)":(".*")($|,)','\1=\2',1,0 
-------------------------------------------------------------------------------- 

a="01/01/2015" 
b="31/12/2015" 
c="11111111111" 
d="1111111111" 
e="1234567890" 

您可以將其用作虛擬XML節點的屬性;將其轉換成XMLType的,你可以使用XMLTable可以提取屬性:

select x.a, x.b, x.c, x.d, x.e 
from tests_1 t 
cross join xmltable('/tmp' 
    passing xmltype('<tmp ' ||regexp_replace(regexp_replace(value, '(^{|}$)'), 
    '^"(.*)":(".*")($|,)', '\1=\2', 1, 0, 'm') || ' />') 
    columns a varchar2(10) path '@a', 
    b varchar2(10) path '@b', 
    c number path '@c', 
    d number path '@d', 
    e number path '@e' 
) x; 

A   B      C    D    E 
---------- ---------- ------------- ------------- ------------- 
01/01/2015 31/12/2015 11111111111 1111111111 1234567890 

然後你就可以在插入過程中轉換成字符串日期:

insert into test_2 (a, b, c, d, e) 
select to_date(x.a, 'DD/MM/YYYY'), to_date(x.b, 'DD/MM/YYYY'), x.c, x.d, x.e 
from tests_1 t 
cross join xmltable('/tmp' 
    passing xmltype('<tmp ' || regexp_replace(regexp_replace(value, '(^{|}$)'), 
    '^"(.*)":(".*")($|,)', '\1=\2', 1, 0, 'm') || ' />') 
    columns a varchar2(10) path '@a', 
    b varchar2(10) path '@b', 
    c number path '@c', 
    d number path '@d', 
    e number path '@e' 
) x; 

select * from test_2; 

A   B      C    D    E 
---------- ---------- ------------- ------------- ------------- 
2015-01-01 2015-12-31 11111111111 1111111111 1234567890 

將與一些名稱/值對應對不在那裏,如果發生這種情況,你會得到空值。

如果所有對將永遠在那裏,你可以只記號化字符串,然後拉出相關部分:

select to_date(regexp_substr(value, '[^"]+', 1, 4), 'DD/MM/YYYY') as a, 
    to_date(regexp_substr(value, '[^"]+', 1, 8), 'DD/MM/YYYY') as b, 
    to_number(regexp_substr(value, '[^"]+', 1, 12)) as c, 
    to_number(regexp_substr(value, '[^"]+', 1, 16)) as d, 
    to_number(regexp_substr(value, '[^"]+', 1, 20)) as e 
from tests_1; 

A   B      C    D    E 
---------- ---------- ------------- ------------- ------------- 
2015-01-01 2015-12-31 11111111111 1111111111 1234567890 
+0

謝謝你的回答。有用。 –

0

Oracle 18c你可以使用TREAT AS JSON operator

SQL增強了JSON

  • 您可以指定一個給定的SQL表達式返回JSON數據,使用TREAT(... AS JSON)。

  • TREAT(... AS JSON)讓您指定來自給定SQL表達式的返回值將被視爲JSON數據。這些表達式可以包括PL/SQL函數調用和由SQL WITH子句指定的列。新的數據指南視圖可以輕鬆訪問JSON字段的路徑和類型信息,這些信息記錄爲索引支持的數據指南。在LOB實例中返回生成和查詢的JSON數據擴大了關係數據的使用範圍。


這個操作符提供了一種方法以通知VARCHAR2,BLOB的內容,CLOB應被視爲含JSON數據庫。 這提供了許多有用的功能,包括對不具有「IS JSON」約束的數據庫對象使用「簡化語法」的功能。

而且在你的榜樣:

create table Test_1(val CLOB); 
create table Test_2(a date,b date,c number,d number, e number); 

INSERT INTO Test_1(val) 
VALUES('{ 
"a":"01/01/2015", 
"b":"31/12/2015", 
"c":"11111111111", 
"d":"1111111111", 
"e":"1234567890" 
}'); 

INSERT INTO Test_2(a,b,c,d,e) 
SELECT val_as_json.a, 
     val_as_json.b, 
     val_as_json.c, 
     val_as_json.d, 
     val_as_json.e 
FROM (SELECT TREAT(val as JSON) val_as_json 
     FROM Test_1) sub; 
COMMIT;