Oracle 12c及以上版本json_table

運行環境:SQLPLUS, SERVEROUTPUT已打開
我有一張用戶表,包含一個JSON列,裏面是他們的社交媒體資料:

create table qz_users (
   id       integer primary key
, username varchar2(10)
, profiles varchar2(4000) check (profiles is json)
)
/

insert into qz_users values (68, 'Benjamin', '[
   { "site" : "twitter"  , "name" : "benjamin68" }
, { "site" : "facebook" , "name" : "benjyface"  }
]')
/
insert into qz_users values (96, 'Barbara', '[
   { "site" : "twitter"  , "name" : "barbiegirl" }
, { "site" : "instagram", "name" : "cutiebarb"  }
, { "site" : "pinterest", "name" : "barb1996"   }
]')
/
commit
/

我想要一個用戶列表,連接到他們的社交媒體資料,有兩個列包含着JSON列表中的site和name屬性的值,如下所示:

        ID USERNAME   SITE       NAME
---------- ---------- ---------- ----------
        68 Benjamin   facebook   benjyface
        68 Benjamin   twitter    benjamin68
        96 Barbara    instagram  cutiebarb
        96 Barbara    pinterest  barb1996
        96 Barbara    twitter    barbiegirl

哪些選項執行不出錯並且產生所示的輸出?


(A)
select u.id, u.username, p.site, p.name
  from qz_users u
     , json_table (
          u.profiles, '$[*]'
          columns (
             site varchar2(10) path '$.site'
           , name varchar2(10) path '$.name'
          )
       ) p
order by u.id, p.site
/

(B)
select u.id, u.username, p.site, p.name
  from qz_users u
     , json_table (
          u.profiles, '$[*]'
          columns (
             site varchar2(10)
           , name varchar2(10)
          )
       ) p
order by u.id, p.site
/

(C)
select u.id, u.username, p.site, p.name
  from qz_users u
     , json_table (
          u.profiles
          columns (
             site varchar2(10)
           , name varchar2(10)
          )
       ) p
order by u.id, p.site
/

(D)
select u.id, u.username, p.site, p.name
  from qz_users u
     , json_table (
          u.profiles
          columns (
             site varchar2(10) path '$[*].site'
           , name varchar2(10) path '$[*].name'
          )
       ) p
order by u.id, p.site
/

(E)
select u.id, u.username, p.site, p.name
  from qz_users u
     , json_table (
          u.profiles
          columns (
             site varchar2(10)
           , name varchar2(10)
          )
       ) p
order by u.id, p.site
/

(F)
select u.id, u.username, p.site, p.name
  from qz_users u
     , json_table (
          u.profiles, '$[*]'
          columns (
             obj varchar2(4000) format json path '$'
          )
       ) o
     , json_table (
          o.obj, '$'
          columns (
             site varchar2(10) path '$.site'
           , name varchar2(10) path '$.name'
          )
       ) p
order by u.id, p.site
/

(G)
select u.id, u.username, p.site, p.name
  from qz_users u
     , json_table (
          u.profiles, '$[*]'
          columns (
             obj varchar2(4000) format json path '$'
          )
       ) o
     , json_table (
          o.obj
          columns (
             site varchar2(10)
           , name varchar2(10)
          )
       ) p
order by u.id, p.site
/

(H)
with p_obj as (
   select u.id, u.username, o.obj
     from qz_users u
        , json_table (
             u.profiles, '$[*]'
             columns (
                obj varchar2(4000) format json path '$'
             )
          ) o
    where rownum > 0
)
select p_obj.id, p_obj.username, p.site, p.name
  from p_obj
     , json_table (
          p_obj.obj, '$'
          columns (
             site varchar2(10) path '$.site'
           , name varchar2(10) path '$.name'
          )
       ) p
order by p_obj.id, p.site
/


(I)
with p_obj as (
   select u.id, u.username, o.obj
     from qz_users u
        , json_table (
             u.profiles, '$[*]'
             columns (
                obj varchar2(4000) format json path '$'
             )
          ) o
    where rownum > 0
)
select p_obj.id, p_obj.username, p.site, p.name
  from p_obj
     , json_table (
          p_obj.obj
          columns (
             site varchar2(10)
           , name varchar2(10)
          )
       ) p
order by p_obj.id, p.site
/

答案ABHI

A: JSON_TABLE的普通用法,指定了“記錄”的路徑以及每條記錄中的列的路徑。
B: 在18C版本中,我們可以跳過制定的列路徑----於是路徑就缺省爲$.{列名}, 這意味着這個選項和前一選項是相同的。
C: 在18C版本中,你還可以跳過A選項中的“記錄”路徑,但是我們不能夠使用[*]這種風格的訪問路徑表達式來得到數組中的每個對象。這會報錯:
ORA-02000: missing COLUMNS keyword.
D: 如果我們完全跳過了[*], 那麼JSON_TABLE的“記錄”就變成了整個數組----因爲我們沒有指定“記錄”路徑,它缺省爲'$',那意味着我們得不到正確的行數,而列路徑不起作用,導致了NULL值,總而言之我夢得到這個錯誤的輸出:

        ID USERNAME   SITE       NAME
---------- ---------- ---------- ----------
        68 Benjamin
        96 Barbara

E: 正如前一選項,JSON_TABLE的“記錄”是整個數組。此處我們只是沒有制定列路徑,所以它們缺省爲 $.site 和 $.name, 當這被應用於數組而不是數組中的對象,就導致了NULL值,所以我們得到了和前一選項相同的錯誤輸出。

F:
原則上,這看起來像一個冗長但有效的與選項A相同的寫法。但它不起作用,會報錯:
ORA-40556: unsupported chaining of JSON_TABLE
隨後的建議是使用NESTED PATH,但是如果我們嘗試就會得到另一個錯誤:
ORA-40561: invalid path in JSON_TABLE nested path clause.
問題是,選擇A做得很好,而這樣做是沒有意義的。

G: 原則上,這似乎比前一選項更有道理,因爲創建O.OBJ列應該允許我們完全跳過第二個JSON_TABLE調用中的JSON路徑說明。但不行的是,我們仍然會得到這個錯誤:
ORA-40556: unsupported chaining of JSON_TABLE.

H: 如果我們利用有個經典技巧,通過使用WHERE ROWNUM > 0把第一個JSON_TABLE的輸出進行“物化”,我們就可以避免前兩個選項的unsupported chaining錯誤。這是可行的,只是多了很多不必要的工作。
I: 利用這個技巧也允許我們跳過第二個JSON_TABLE中的路徑表達式並且使得缺省值和前一選項完全一樣。

 

 

其他DEMO處理展示:

--從JSONArray中取數據
SELECT jt.*
FROM JSON_TABLE('[
        {
            "device_type_id": 1,
            "amount": 120,
            "remarks": ""
        },
        {
            "device_type_id": 2,
            "amount": 122,
            "remarks": ""
        },
        {
            "device_type_id": 3,
            "amount": 123,
            "remarks": "11111111111"
        }
    ]','$'COLUMNS(NESTED PATH '$[*]' COLUMNS (device_type_id VARCHAR2(32) PATH '$.device_type_id',amount VARCHAR2(32) PATH '$.amount',remarks VARCHAR2(32) PATH '$.remarks')))
AS jt;
 
--從JSONObject對象中取數據
SELECT jt.*
FROM JSON_TABLE('{
    "detailed": [
        {
            "device_type_id": 1,
            "amount": 120,
            "remarks": ""
        },
        {
            "device_type_id": 2,
            "amount": 122,
            "remarks": ""
        }
    ]
}
','$'
COLUMNS
(NESTED PATH '$.detailed[*]' COLUMNS (device_type_id VARCHAR2(32) PATH '$.device_type_id',amount VARCHAR2(32) PATH '$.amount',remarks VARCHAR2(32) PATH '$.remarks')))
AS jt;
 
SELECT *
  FROM JSON_TABLE('{
                    "device_type_id": "1",
                    "amount": "120",
                    "remarks": ""
                }
',
                   '$' COLUMNS(outer_value_0 NUMBER PATH '$.device_type_id',
                           outer_value_1 NUMBER PATH '$.amount'));
 
--從三層嵌套的JSONObject對象中取數據
SELECT jt.*
FROM JSON_TABLE('{
    "certificate": "14531209693428a799591c0248bb95c3",
    "rows": [
        {
            "odo_id": "0",
            "odo_no": "ZC-FY-20170217001",
            "stamp": "2017-02-24",
            "order_no": "ZC-DD-20170210001",
            "partners_id": "213",
            "shipping_address": "深圳市福田區科技園南區T2-B棟601",
            "contacts": "李魁",
            "tel": "13510141822",
            "self_mention": "0",
            "detailed": [
                {
                    "device_type_id": "1",
                    "amount": "121",
                    "remarks": ""
                },{
                    "device_type_id": "2",
                    "amount": "122",
                    "remarks": ""
                }
            ]
        },{
            "odo_id": "0",
            "odo_no": "ZC-FY-20170217002",
            "stamp": "2017-02-24",
            "order_no": "ZC-DD-20170210001",
            "partners_id": "213",
            "shipping_address": "深圳市福田區科技園南區T2-B棟601",
            "contacts": "李魁",
            "tel": "13510141822",
            "self_mention": "0",
            "detailed": [
                {
                    "device_type_id": "3",
                    "amount": "123",
                    "remarks": ""
                },{
                    "device_type_id": "4",
                    "amount": "124",
                    "remarks": ""
                }
            ]
        }
    ]
}
', '$'
COLUMNS
  (requestor VARCHAR2(32) PATH '$.certificate',NESTED PATH '$.rows[*]' COLUMNS (odo_no VARCHAR2(32) PATH '$.odo_no',NESTED PATH '$.detailed[*]' COLUMNS (phone_type VARCHAR2(32) PATH '$.device_type_id', phone_num VARCHAR2(20) PATH '$.amount'))))
AS jt;

原文鏈接:http://www.itpub.net/thread-2109001-1-1.html  (newkid)

https://blog.csdn.net/e_wsq/article/details/60150077 

【侵權刪】

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章