PostgreSQL 将未定义的 JSONB 字段动态转换为一行

Cyb*_*lle 5 postgresql select json

我有一个类型为字段的表jsonb,我想为所有 json 键拆分字段 jsonb 的列。此列缺少架构。例如:

CREATE TABLE v(id,jsonb)
  AS VALUES
    (1,'{"a":"4", "b":"5"}'::jsonb),
    (2,'{}'),
    (3,'{"a":"8", "c":"9", "d":"9"}');
Run Code Online (Sandbox Code Playgroud)

id  |  a   |   b   |  c  |  d

1   |  4   |   5   |     |  
3   |  8   |       |  9  |  9
Run Code Online (Sandbox Code Playgroud)

对于这种特定情况,一种解决方案是

select * from table, json_to_record(optional) as x("a" text, "b" text, "c" text, d text)
Run Code Online (Sandbox Code Playgroud)

如您所见,键可能会有所不同,并且在大型数据库中很难将所有键都放在我的实际问题中,我有 31 个键,另一方面,如果我想在其他表中重用此脚本,我必须手动填充键。

有没有办法在 jsonb 的所有键上进行选择而无需手动指定键?

Eva*_*oll 1

我的问题:有没有办法在 jsonb 的所有键上进行选择,而无需手动指定键?

不可以,因为没有办法让查询返回未定义的结果集。但是,如果表不接受新查询,您可以生成动态 sql 语句。

SELECT FORMAT(
  $$ SELECT * FROM %I.%I CROSS JOIN LATERAL jsonb_to_record(%I) AS rs(%s); $$,
  'public',
  'v',
  'jsonb',
  array_to_string(
                (SELECT ARRAY(SELECT DISTINCT col FROM v CROSS JOIN LATERAL jsonb_object_keys(jsonb) AS t(col) ORDER BY col)), ' text , '
  ) || ' text'
);
Run Code Online (Sandbox Code Playgroud)

然后运行该查询,或\gexec在 psql 中运行。

                                                    format                                                    
--------------------------------------------------------------------------------------------------------------
  SELECT * FROM public.v CROSS JOIN LATERAL jsonb_to_record(jsonb) AS rs(a text , b text , c text , d text); 
(1 row)

test=# \gexec
 id |             jsonb              | a | b | c | d 
----+--------------------------------+---+---+---+---
  1 | {"a": "4", "b": "5"}           | 4 | 5 |   | 
  2 | {}                             |   |   |   | 
  3 | {"a": "8", "c": "9", "d": "9"} | 8 |   | 9 | 9
(3 rows)
Run Code Online (Sandbox Code Playgroud)

您可能想也可能不想构建一些jsonb_typeof返回 pg 类型的类型推断:请记住,您永远不能返回整数或其他东西,但您应该能够将数字存储为double precision.