PostgreSQL jsonb_path_query 删除结果而不是返回空值

Isa*_*c N 5 sql postgresql jsonpath set-returning-functions jsonb

在示例表中:

CREATE TABLE example (
    id   SERIAL PRIMARY KEY,
    data JSON NOT NULL );
INSERT INTO example (id, data) VALUES
  (1, '[{"key": "1", "value": "val1"}, {"key": "2", "value": "val2"}]')
, (2, '[{"key": "1", "value": "val1"}]')
, (3, '[{"key": "1", "value": "val1"}, {"key": "2", "value": "val2"}]');
Run Code Online (Sandbox Code Playgroud)

我想查询数据列中 key = 2 的值字段。我当前使用的查询是这样的:

SELECT id,
       jsonb_path_query(
               TO_JSONB(data),
               '$[*] ? (@.key == "2").value'::JSONPATH
           )::VARCHAR AS values
FROM example
Run Code Online (Sandbox Code Playgroud)

我期望结果是:

ID 价值观
1 “值2”
2 无效的
3 “值2”

但实际结果是:

ID 价值观
1 “值2”
3 “值2”

省略 null 输出是否有原因jsonb_path_query()
我如何让它按照我期望的方式运行?

Zeg*_*rek 6

标量函数处理一个值,并且可以使该值无效,但是返回集合的函数 会生成值,因此它最终可能根本不生成值。正如已经建议的,您可以使用标量函数

\n
SELECT id, jsonb_path_query_first(data::jsonb, \'$[*]?(@.key=="2").value\')\nFROM example;\n
Run Code Online (Sandbox Code Playgroud)\n

或者,您可以通过将 SRF(集合返回函数)jsonb_path_query()\xe2\x86\x92 setof jsonb包装在标量子查询中或替换其隐式内部联接来保留它。两者都会用 null 来指示缺少生成的值,但后者仍然可以生成并返回多个:demo

\n
SELECT id,(SELECT jsonb_path_query(data::jsonb,\'$[*]?(@.key=="2").value\')LIMIT 1)\nFROM example;\n\nSELECT id, values\nFROM example LEFT JOIN jsonb_path_query(data::jsonb, \'$[*]?(@.key=="2").value\') \n                       AS srf(values) \n             ON true;\n
Run Code Online (Sandbox Code Playgroud)\n

第 2 行没有在该函数中生成任何行,这就是您没有看到它的原因 - 没有行可以进入null。选择部分不是SRF 的正常位置- 当应用到此处时,它结束向上推向下至from节要inner joined带。有了inner join空集,就是空集。这与隐式连接行为相结合,就是为什么您可以阅读:

\n
    \n
  • SELECT srf();作为实际的SELECT b.x FROM srf() AS b(x);

    \n
  • \n
  • SELECT a.id, srf() FROM a;意义SELECT a.id, b.x FROM a, srf() AS b(x);

    \n
  • \n
  • SELECT a.id, b.x FROM a, srf(a.v) AS b(x);实际上的意思是SELECT a.id, srf(a.v) FROM a;

    \n

    SELECT a.id, b.x FROM a INNER JOIN srf(a.v) AS b(x) ON true;

    \n
  • \n
\n

INNER JOIN抛出了你id没有 result-genening 的 s dataLEFT JOIN惯于。

\n
\n

另一个插图更明显generate_series()“给我这么多行”SRF:演示

\n
create table table1(id smallserial, how_many_to_generate int);\ninsert into table1(how_many_to_generate) values (1),(0),(2),(0),(1);\n\n--no rows for the 2nd and 4th entry where `how_many_to_generate` is 0\n--on the other hand, the 3rd entry requested and received two rows\nselect id, how_many_to_generate, generate_series(1, how_many_to_generate)\nfrom table1;\n-- id | how_many_to_generate | generate_series\n------+----------------------+-----------------\n--  1 |                    1 |               1\n--  3 |                    2 |               1\n--  3 |                    2 |               2\n--  5 |                    1 |               1\n
Run Code Online (Sandbox Code Playgroud)\n


小智 4

jsonb_path_query_first()如果您想要路径表达式的结果,您需要:

SELECT id,
       jsonb_path_query_first(data, '$[*] ? (@.key == "2").value') AS values
FROM example
Run Code Online (Sandbox Code Playgroud)

请注意,这会返回一个jsonb值。如果您想要一个text值,请使用:

jsonb_path_query_first(data, '$[*] ? (@.key == "2").value') #>> '{}
Run Code Online (Sandbox Code Playgroud)