Postgres 强制使用 COALESCE 而值不能为 null

问题描述 投票:0回答:1

我在 Postgres 上运行一个令人不安的请求,无法弄清楚以下几点。

注意:以下请求不需要表格,您可以在任何 postgres 提示符下尝试。

给定以下示例数据:

SELECT
*
FROM jsonb_to_recordset('[{"cat": "A", "key": null, "value": null}, {"cat": "A", "key": "key_A", "value": "val_A"}, {"cat": "B", "key": null, "value": null}, {"cat": "C", "key": "key_C", "value": "val_C"}]')
AS x(cat text, key text, value text);
 cat |  key  | value 
-----+-------+-------
 A   |       | 
 A   | key_A | val_A
 B   |       | 
 C   | key_C | val_C
(4 rows)

以下查询工作正常:

SELECT
cat,
CASE WHEN bool_or(key IS NULL) THEN null
ELSE
   jsonb_object_agg(COALESCE(key, '???'), value)
END AS obj
FROM jsonb_to_recordset('[{"cat": "A", "key": null, "value": null}, {"cat": "A", "key": "key_A", "value": "val_A"}, {"cat": "B", "key": null, "value": null}, {"cat": "C", "key": "key_C", "value": "val_C"}]')
AS x(cat text, key text, value text)
GROUP BY cat 
 cat |        obj         
-----+--------------------
 B   | 
 C   | {"key_C": "val_C"}
 A   | 
(3 rows)

但我不明白为什么我必须使用

COALESCE
,因为我猜此时值不能为空(正如您在结果中看到的那样,没有
???
键。

但是,当我删除

COALESCE
时:

SELECT
cat,
CASE WHEN bool_or(key IS NULL) THEN null
ELSE
   jsonb_object_agg(key, value)
END AS obj
FROM jsonb_to_recordset('[{"cat": "A", "key": null, "value": null}, {"cat": "A", "key": "key_A", "value": "val_A"}, {"cat": "B", "key": null, "value": null}, {"cat": "C", "key": "key_C", "value": "val_C"}]')
AS x(cat text, key text, value text)
GROUP BY cat 
psql:commands.sql:9: ERROR:  field name must not be null

我将不胜感激!干杯。

postgresql aggregate-functions
1个回答
0
投票

同时计算每一行的聚合。

jsonb_object_agg()
的第一个值是在
bool_or()
的结果未知时计算的。你可以用一个简单的自定义聚合来说明这个机制:

create or replace function my_agg_function(int, int)
returns int language plpgsql as $$
begin
    raise notice 'called for %', $2;
    return coalesce($1, 0)+ coalesce($2, 0);
end $$;

create aggregate my_agg(int) (
    sfunc = my_agg_function,
    stype = int);

在下面的查询中,

my_agg_function()
被执行了三次,因为
bool_or()
的结果只有在处理完所有行后才知道:

select case when bool_or(i = 10) then my_agg(i) end
from generate_series(1, 3) as i;

NOTICE:  called for 1
NOTICE:  called for 2
NOTICE:  called for 3
 case
------

(1 row)
© www.soinside.com 2019 - 2024. All rights reserved.