2017-02-22 174 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)