postgresql - sql - 计算`true`值

Eog*_*anM 81 sql postgresql

myCol
------
 true
 true
 true
 false
 false
 null
Run Code Online (Sandbox Code Playgroud)

在上表中,如果我这样做:

select count(*), count(myCol);
Run Code Online (Sandbox Code Playgroud)

我明白了 6, 5

我得到5因为它不计入null条目.

我如何计算真值的数量(示例中为3)?

(这是一个简化,我实际上在count函数中使用了一个更复杂的表达式)

编辑摘要:我还想在查询中包含普通计数(*),因此不能使用where子句

Dan*_*iel 114

SELECT COALESCE(sum(CASE WHEN myCol THEN 1 ELSE 0 END),0) FROM <table name>
Run Code Online (Sandbox Code Playgroud)

或者,正如你自己发现的那样:

SELECT count(CASE WHEN myCol THEN 1 END) FROM <table name>
Run Code Online (Sandbox Code Playgroud)

  • 不......只是因为我不确定哪些值会计数()计数......而且我知道总和就行了.但要注意:第二个想法我认为sum()只有null值会返回null,所以它应该是COALESCE(sum(...),0),换句话说,count()更好, (5认同)
  • 还有,您为什么使用sum(.. THEN 1 ELSE 0)而不是count(.. THEN true否则为null)的任何原因? (2认同)
  • 实际上,您可以省略“ELSE null”来获得相同的结果。 (2认同)
  • 您还可以使用 COUNT() 执行更多深奥的应用程序,例如“COUNT(DISTINCT CASE WHEN mycol2 THEN mycol1 END)”,它在 mycol2 为 true 时对不同的 mycol1 进行计数 (2认同)

Dwa*_*ell 73

将布尔值转换为整数和求和.

SELECT count(*),sum(myCol::int);
Run Code Online (Sandbox Code Playgroud)

你得到6,3.

  • “转换为 int 并计数”显然是最简洁的,但这并不是最好的。我不赞同这一点,因为虽然许多环境使用 0/1 表示 false/true,但许多环境使用 0/非零,包括 -1。我同意这是一个“黑客”,当他们不是“黑客”时,演员阵容就足够冒险了。不会投反对票,但再次不会支持。 (4认同)
  • 加1:很好的黑客!这可能比我的解决方案更快. (3认同)

Ilj*_*ilä 64

从PostgreSQL 9.4开始,有一个FILTER子句,允许非常简洁的查询来计算真值:

select count(*) filter (where myCol)
from tbl;
Run Code Online (Sandbox Code Playgroud)

上面的查询是一个不好的例子,因为一个简单的WHERE子句就足够了,并且仅用于演示语法.FILTER子句闪耀的地方是很容易与其他聚合结合:

select count(*), -- all
       count(myCol), -- non null
       count(*) filter (where myCol) -- true
from tbl;
Run Code Online (Sandbox Code Playgroud)

该子句对于使用另一列作为谓词的列上的聚合特别方便,同时允许在单个查询中获取不同的筛选聚合:

select count(*),
       sum(otherCol) filter (where myCol)
from tbl;
Run Code Online (Sandbox Code Playgroud)

  • 把它作为最佳答案......更容易 (7认同)
  • 这是PG&gt; 9.4的最佳答案,而且速度非常快 (2认同)

wro*_*ell 44

可能,最好的方法是使用nullif函数.

一般来说

select
    count(nullif(myCol = false, true)),  -- count true values
    count(nullif(myCol = true, true)),   -- count false values
    count(myCol);
Run Code Online (Sandbox Code Playgroud)

或简而言之

select
    count(nullif(myCol, true)),  -- count false values
    count(nullif(myCol, false)), -- count true values
    count(myCol);
Run Code Online (Sandbox Code Playgroud)

http://www.postgresql.org/docs/9.0/static/functions-conditional.html

  • 你的"一般"看起来不对:AFAICS,`nullif([boolean expression],true)`如果[boolean expression]为false则返回`false`,如果为true则返回'null`,所以你将计算false值.我想你想要`nullif([boolean expression],false)`. (2认同)

Le *_*oid 18

最短和最懒的(没有铸造)解决方案是使用公式:

SELECT COUNT(myCol OR NULL) FROM myTable;
Run Code Online (Sandbox Code Playgroud)

亲自尝试一下:

SELECT COUNT(x < 7 OR NULL)
   FROM GENERATE_SERIES(0,10) t(x);
Run Code Online (Sandbox Code Playgroud)

给出了相同的结果

SELECT SUM(CASE WHEN x < 7 THEN 1 ELSE 0 END)
   FROM GENERATE_SERIES(0,10) t(x);
Run Code Online (Sandbox Code Playgroud)


小智 8

只需将布尔字段转换为整数并进行求和即可.这将适用于postgresql:

select sum(myCol::int) from <table name>
Run Code Online (Sandbox Code Playgroud)

希望有所帮助!


Kub*_*aun 7

select f1,
       CASE WHEN f1 = 't' THEN COUNT(*) 
            WHEN f1 = 'f' THEN COUNT(*) 
            END AS counts,
       (SELECT COUNT(*) FROM mytable) AS total_counts
from mytable
group by f1
Run Code Online (Sandbox Code Playgroud)

或者也许这个

SELECT SUM(CASE WHEN f1 = 't' THEN 1 END) AS t,
       SUM(CASE WHEN f1 = 'f' THEN 1 END) AS f,
       SUM(CASE WHEN f1 NOT IN ('t','f') OR f1 IS NULL THEN 1 END) AS others,
       SUM(CASE WHEN f1 IS NOT NULL OR f1 IS NULL THEN 1 ELSE 0 END) AS total_count
FROM mytable;
Run Code Online (Sandbox Code Playgroud)


ype*_*eᵀᴹ 6

在MySQL中,您也可以这样做:

SELECT count(*) AS total
     , sum(myCol) AS countTrue --yes, you can add TRUEs as TRUE=1 and FALSE=0 !!
FROM yourTable
;
Run Code Online (Sandbox Code Playgroud)

我认为在Postgres中,这有效:

SELECT count(*) AS total
     , sum(myCol::int) AS countTrue --convert Boolean to Integer
FROM yourTable
;
Run Code Online (Sandbox Code Playgroud)

或更好(避免::并使用标准SQL语法):

SELECT count(*) AS total
     , sum(CAST(myCol AS int)) AS countTrue --convert Boolean to Integer
FROM yourTable
;
Run Code Online (Sandbox Code Playgroud)


Uly*_* BN 5

基准

TL;DR:采取您喜欢的解决方案。没有显着差异。

实用脚本

before(){
    psql <<-SQL
        create table bench (
                id         serial
            , thebool    boolean
        );

        insert into bench (thebool)
        select (random() > 0.5)
        from generate_series(1, 1e6) g;


        analyze bench;
    SQL
}
after(){
    psql -c 'drop table bench'
}
test(){
    echo $(tput bold)$1$(tput sgr0)
    psql -c "explain analyze select $1 from bench" | tail -4 | head -2
}
Run Code Online (Sandbox Code Playgroud)

实际基准

在 1.4GHz i5 MacBookPro、psql 和 pg 12.4 上制作(pg 在 Linux docker 容器中):

before  
test 'count(*) filter (where thebool)'
# Planning Time: 0.138 ms
# Execution Time: 4424.042 ms
test 'count(case when thebool then 1 end)'
# Planning Time: 0.156 ms
# Execution Time: 4638.861 ms
test 'count(nullif(thebool, false))'
# Planning Time: 0.201 ms
# Execution Time: 5267.631 ms
test 'count(thebool or null)'
# Planning Time: 0.202 ms
# Execution Time: 4672.700 ms
test 'sum(thebool::integer)'
# Planning Time: 0.155 ms
# Execution Time: 4602.406 ms
test 'coalesce(sum(case when thebool THEN 1 ELSE 0 END), 0)'
# Planning Time: 0.167 ms
# Execution Time: 4416.503 ms
after
Run Code Online (Sandbox Code Playgroud)