rob*_*obx 9 postgresql null sum aggregate-functions
我希望聚合列的总和,同时跟踪是否存在表示错误情况的NULL值.例如,取表号码:
# select * from numbers;
n | l
------+-----
1 | foo
2 | foo
NULL | bar
4 | bar
Run Code Online (Sandbox Code Playgroud)
给定一个标签l,我想计算n带有该标签的数字总和,前提是没有NULL值.理想情况下,对于没有任何行的一个标签,总和将是0,所以我在寻找一些查询q,从而
q('foo') = 3,q('baz') = 0并q('bar')以某种方式发出错误信号,例如,通过返回NULL.
我从sum() 聚合函数开始,但是将NULL行转换为0.一个解决方案是返回,NULL只要有任何NULL值.
sum() 给
# select sum(n) from numbers where l = 'bar';
sum
-----
4
Run Code Online (Sandbox Code Playgroud)
但我宁愿和你sumnull()在一起
# select sumnull(n) from numbers where l = 'bar';
sumnull
---------
NULL
Run Code Online (Sandbox Code Playgroud)
到目前为止,我发现的最佳解决方案是计算非NULL行并与总计数进行比较:
# select sum(n), count(*), count(n) as notnull from numbers;
sum | count | notnull
-----+-------+---------
7 | 4 | 3
Run Code Online (Sandbox Code Playgroud)
如果count不相等notnull,我知道结果无效.
空集是否足够好?
create table numbers (n int);
insert into numbers values (1),(2),(null),(4);
select sum(n)
from numbers
having bool_and(n is not null);
sum
-----
(0 rows)
Run Code Online (Sandbox Code Playgroud)
如果你真的需要一个空值,它会有点复杂:
with sum_null as (
select sum(n) as sum_n
from numbers
having bool_and(n is not null)
)
select case
when not exists (select 1 from sum_null) then null
else (select sum_n from sum_null) end
;
sum_n
-------
(1 row)
Run Code Online (Sandbox Code Playgroud)
替换having为:
having not bool_or(n is null)
Run Code Online (Sandbox Code Playgroud)
不太可读但可能更快,因为它可以在第一次null找到时停止搜索.
https://www.postgresql.org/docs/current/static/functions-aggregate.html#FUNCTIONS-AGGREGATE-TABLE
您可以创建自定义聚合,例如:
create or replace function int_sum_null(int, int)
returns int language sql as $$
select $1 + $2
$$;
create aggregate sumnull(integer) (
sfunc = int_sum_null,
stype = int
);
select sum(n), sumnull(n)
from numbers;
sum | sumnull
-----+---------
7 | <null>
(1 row)
Run Code Online (Sandbox Code Playgroud)
更新#1
没有自定义聚合的解决方案
select case
when bool_or(n is null) then null
else sum(n) end
from numbers;
select coalesce((
select sum(n)
from numbers
having not bool_or(n is null)), null);
Run Code Online (Sandbox Code Playgroud)
这些变体基于Clodoaldo Neto的想法.如果你喜欢他们,请同意他的回答.
更新#2
修改自定义聚合sumnull并添加初始条件:
drop aggregate sumnull(integer);
create aggregate sumnull(integer) (
sfunc = int_sum_null,
stype = int,
initcond = 0
);
Run Code Online (Sandbox Code Playgroud)
获取您在更新的问题中描述的结果:
create table numbers (n int, l text);
insert into numbers values
(1, 'foo'), (2, 'foo'), (null, 'bar'), (4, 'bar');
select
sumnull(n) filter (where l = 'foo') foo,
sumnull(n) filter (where l = 'bar') bar,
sumnull(n) filter (where l = 'baz') baz
from numbers;
foo | bar | baz
-----+-----+-----
3 | | 0
(1 row)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6459 次 |
| 最近记录: |