提问者:小点点

为什么PostgreSQL中的聚合函数不适用于布尔数据类型


为什么我们不能在聚合函数中使用布尔值而不首先转换为某种整数类型?在许多情况下,从布尔数据类型的列计算总和、平均值或相关性是非常有意义的。

考虑以下示例,其中必须始终将布尔输入强制转换为int才能使其工作:

select
   sum(boolinput::int),
   avg(boolinput::int),
   max(boolinput::int),
   min(boolinput::int),
   stddev(boolinput::int),
   corr(boolinput::int,boolinputb::int)   
from
   (select 
      (random() > .5)::boolean as boolinput,
      (random() > .5)::boolean as boolinputB 
    from 
      generate_series(1,100)
   ) a

从PostgreSQL留档:

“true”状态的有效文字值是:TRUE't''true''y''yes''on'1'

对于“false”状态,可以使用以下值:FALSE'f''false''n''no''off''0'

因为根据定义TRUE等于1FALSE等于0我不明白为什么需要转换。

在聚合中允许布尔值也会产生有趣的副作用——例如,我们可以简化许多case语句:

当前版本(干净易懂):

select sum(case when gs > 50 then 1 else 0 end) from generate_series(1,100) gs;

使用老式的铸造运算符::

select sum((gs > 50)::int) from generate_series(1,100) gs;

布尔值的直接聚合(目前不起作用):

select sum(gs > 50) from generate_series(1,100) gs;

在其他DBMS中是否可以直接聚合布尔值?为什么这在PostgreSQL中是不可能的?


共3个答案

匿名用户

因为根据定义,TRUE等于1,FALSE等于0,我不明白为什么需要转换。

根据您在问题中引用的文档,根据定义,布尔值不是1代表TRUE,0代表FALSE。在C中也不是真的,其中TRUE是任何非零的东西。

就此而言,在这方面模仿C的语言也不是这样,其中有很多。也不适用于Ruby等语言,其中任何非Nil/non-False的计算结果都为True,包括零和空字符串。POSIX shell及其变体也不是这样,如果测试返回码为零,则会得到TRUE,对于任何非零的东西,则会得到FALSE。

重点是,布尔值就是布尔值,从一个平台到下一个平台有各种丰富多彩的实现细节;不是整数。

不清楚你是如何期望Postgres平均真/假值的。我怀疑许多(如果有的话)平台会为此产生结果。

即使对布尔值求和也很尴尬:期望Postgres或输入值,或计算TRUE值吗?

无论如何,有一些布尔聚合函数,即bool_or()bool_and()。它们取代了更标准的any()一些()。Postgres在这里偏离标准的原因是由于潜在的歧义。根据文档:

SELECT b1 = ANY((SELECT b2 FROM t2 ...)) FROM t1 ...;

在这里,如果子查询返回一行带有布尔值,则ANY可以被视为引入子查询,也可以被视为聚合函数。

http://www.postgresql.org/docs/current/static/functions-aggregate.html

匿名用户

这里有一些可能性

select max(c::int)::boolean, min(c::int)::boolean, bool_or(c) as max_b,bool_and(c) as min_b from
(
        select false as c
  union select true
  union select null
) t

匿名用户

以下是如何实现max(布尔值)

CREATE AGGREGATE max(boolean) (
  SFUNC=boolor_statefunc,
  STYPE=bool,
  SORTOP=">"
);  

其中“boolor_statefunc”内置功能