2017-02-22 214 views
1

我期待看到如何拼合嵌套在JSONB列中的數據。 作爲一個例子,假設我們有USER_ID(int)和兄弟姐妹(JSONB)拼合Postgres嵌套JSONB列

表用戶有了這樣行:

id | JSONB 
--------------------- 
1 | {"brother": {"first_name":"Sam", "last_name":"Smith"}, "sister": {"first_name":"Sally", "last_name":"Smith"} 
2 | {"sister": {"first_name":"Jill"}} 

我正在尋找一個查詢,將返回類似這樣的回覆:

id | sibling | first_name | last_name 
------------------------------------- 
1 | "brother" | "Sam"  | "Smith" 
1 | "sister" | "Sally" | "Smith" 
2 | "sister" | "Jill"  | null 
+0

postgres版本? –

+0

@VaoTsun版本9.4.9 –

+0

json keys first_name和last_name是不變的?.. –

回答

1

我發展到這個使用它在psql。 要檢查代碼中,我創建小視圖t1

CREATE VIEW t1 AS (
     SELECT 1 AS id, '{"brother": {"first_name":"Sam", "last_name":"Smith"}, "sister": {"first_name":"Sally", "last_name":"Smith"}}'::jsonb AS jsonb 
UNION SELECT 2, '{"sister": {"first_name":"Jill", "last_name":"Johnson"}}' 
UNION SELECT 3, '{"sister": {"first_name":"Jill", "x_name":"Johnson"}}' 
); 

的第一個任務是可能的密鑰的發現名單:

WITH fields AS (
    SELECT DISTINCT jff.key 
     FROM t1, 
      jsonb_each(jsonb) AS jf, 
      jsonb_each(jf.value) AS jff 
) 
SELECT * FROM fields; 

結果是:

key  
------------ 
first_name 
last_name 
x_name 

下一步是生成查詢:

SELECT 'SELECT id, jf.key as sibling, ' || (
    WITH fields AS (
     SELECT DISTINCT jff.key 
      FROM t1, 
       jsonb_each(jsonb) AS jf, 
       jsonb_each(jf.value) AS jff 
    ) 
    SELECT string_agg('jf.value->>''' || key || ''' as "' || key || '"', ',' ORDER BY key) 
     FROM fields 
) 
|| ' FROM t1, jsonb_each(jsonb) AS jf ORDER BY 1, 2, 3;' AS cmd; 

它返回:

                    cmd                     
------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 
SELECT id, jf.key as sibling,jf.value->>'first_name' as "first_name",jf.value->>'last_name' as "last_name",jf.value->>'x_name' as "x_name" FROM t1, jsonb_each(jsonb) AS jf ORDER BY 1, 2, 3; 
(1 row) 

要設置的結果PSQL變量我使用gset

\gset 

之後,你可以打電話查詢:

:cmd 

id | sibling | first_name | last_name | x_name 
----+---------+------------+-----------+--------- 
    1 | brother | Sam  | Smith  | 
    1 | sister | Sally  | Smith  | 
    2 | sister | Jill  | Johnson | 
    3 | sister | Jill  |   | Johnson 
(4 rows) 

從外部語言運行它,你可以創建postgres函數而不是返回SQL命令:

CREATE OR REPLACE FUNCTION build_query(IN tname text, OUT cmd text) AS $sql$ 
BEGIN 
    EXECUTE $cmd$ 
      SELECT 'SELECT id, jf.key as sibling, ' || (
        WITH fields AS (
         SELECT DISTINCT jff.key 
          FROM t1, 
           jsonb_each(jsonb) AS jf, 
           jsonb_each(jf.value) AS jff 
        ) 
        SELECT string_agg('jf.value->>''' || key || ''' as "' || key || '"', ',' ORDER BY key) 
         FROM fields 
       ) 
     || ' FROM $cmd$ || quote_ident(tname) || $cmd$ , jsonb_each(jsonb) AS jf ORDER BY 1, 2, 3;'$cmd$ INTO cmd; 
    RETURN; 
END; 
$sql$ LANGUAGE plpgsql; 

SELECT * FROM build_query('t1'); 
                           cmd                        
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
SELECT id, jf.key as sibling, jf.value->>'first_name' as "first_name",jf.value->>'last_name' as "last_name",jf.value->>'x_name' as "x_name" FROM t1 , jsonb_each(jsonb) AS jf ORDER BY 1, 2, 3; 
(1 row)