postgresql - sql - `true` 值的计数
Posted
技术标签:
【中文标题】postgresql - sql - `true` 值的计数【英文标题】:postgresql - sql - count of `true` values 【发布时间】:2011-03-22 19:07:51 【问题描述】:myCol
------
true
true
true
false
false
null
在上表中,如果我这样做:
select count(*), count(myCol);
我收到6, 5
我得到5
,因为它不计算空条目。
我如何也计算真值的数量(示例中为 3)?
(这是一种简化,实际上我在 count 函数中使用了更复杂的表达式)
编辑摘要:我还想在查询中包含一个普通的 count(*),所以不能使用 where 子句
【问题讨论】:
't' 代表 True 和 'f' 代表 False 吗?或者您是否在寻找类似 SELECT COUNT(DISTINCT myCol) 的东西。 看看我的第二个例子,如果你愿意,你可以在里面扔一个WHERE myCol = true
,如果你删除第一个*,
,它只会返回数字。
@Shamit yes t 代表 true,f 代表 false,我已经更新了问题
您最好不要简化您的问题/查询...您的要求限制了更好的性能可能性,人们以低效的答案做出回应,这些答案无缘无故地被提高了。
@vol7ron 在我的辩护中,为了提出一个易于理解的问题,必须进行一些简化,但是是的,我最初发布时过于简化了。
【参考方案1】:
SELECT COALESCE(sum(CASE WHEN myCol THEN 1 ELSE 0 END),0) FROM <table name>
或者,正如你自己发现的那样:
SELECT count(CASE WHEN myCol THEN 1 END) FROM <table name>
【讨论】:
另外,你为什么用 sum(.. THEN 1 ELSE 0) 而不是 count(.. THEN true else null) ? 不...只是我不确定哪些值会 count() 计数...而且我知道 sum 可以解决问题。但要注意:再想一想,我相信 sum() 仅对 null 值会返回 null,所以它应该是 COALESCE(sum(...),0) ,或者换句话说, count() 更好, 谢谢!从未想过我的查询会在一百万年后起作用! @EoghanM,请参阅涉及演员阵容的简短答案。 您实际上可以省略ELSE null
以获得相同的结果。【参考方案2】:
从 PostgreSQL 9.4 开始有了FILTER
clause,它允许非常简洁的查询来计算真实值:
select count(*) filter (where myCol)
from tbl;
上面的查询是一个不好的例子,一个简单的 WHERE 子句就足够了,并且仅用于演示语法。 FILTER 子句的亮点在于它很容易与其他聚合组合:
select count(*), -- all
count(myCol), -- non null
count(*) filter (where myCol) -- true
from tbl;
该子句对于使用另一列作为谓词的列上的聚合特别方便,同时允许在单个查询中获取不同过滤的聚合:
select count(*),
sum(otherCol) filter (where myCol)
from tbl;
【讨论】:
【参考方案3】:将布尔值转换为整数并求和。
SELECT count(*),sum(myCol::int);
你会得到6,3
。
【讨论】:
Plus1:不错的技巧!这可能比我的解决方案还要快。 这是最好和最短的解决方案(并且在许多其他编程环境和软件中具有等效性)。应该更多地投票 'cast to int and count' 显然是最简洁的,但这并不是最好的。我不会赞同这一点,因为虽然许多环境使用 0/1 表示假/真,但许多环境使用 0/非零,包括 -1。我同意这是一个“黑客”,当他们不是“黑客”时,演员阵容就足够冒险了。不会投反对票,但不会再次支持。【参考方案4】:可能,最好的方法是使用 nullif 函数。
一般
select
count(nullif(myCol = false, true)), -- count true values
count(nullif(myCol = true, true)), -- count false values
count(myCol);
简而言之
select
count(nullif(myCol, true)), -- count false values
count(nullif(myCol, false)), -- count true values
count(myCol);
http://www.postgresql.org/docs/9.0/static/functions-conditional.html
【讨论】:
你的“一般”看起来是错误的:AFAICS,nullif([boolean expression], true)
将返回 false
如果 [boolean expression] 为假,null
如果它是真的,所以你会算作假价值观。我想你想要nullif([boolean expression], false)
。
是的,“一般”情况应该是相反的。固定的。谢谢。
哎呀。这个修复真的很混乱。 AFAICS,它现在将计算真值或空值。我认为改写它以便您始终拥有nullif([boolean expression], false)
使其更易于阅读。然后,您可以将布尔表达式部分更改为您喜欢的任何内容,在这种情况下,myCol = true
用于计算真值,myCol = false
用于计算错误值,或name='john'
用于计算称为 john 的人等。【参考方案5】:
最短和最懒(不强制转换)的解决方案是使用以下公式:
SELECT COUNT(myCol OR NULL) FROM myTable;
自己试试吧:
SELECT COUNT(x < 7 OR NULL)
FROM GENERATE_SERIES(0,10) t(x);
给出与
相同的结果SELECT SUM(CASE WHEN x < 7 THEN 1 ELSE 0 END)
FROM GENERATE_SERIES(0,10) t(x);
【讨论】:
这绝对是比我更好的解决方案 :) 非常有见地的答案。【参考方案6】: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
或者也许这个
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;
【讨论】:
+1 如果myCol
表达式是布尔值,您可以将检查替换为where (myCol)
抱歉,我的示例过于简单了:我不能使用 where 子句,因为我还想返回表示总行数的总计数以及真实值的计数。跨度>
【参考方案7】:
在 mysql 中,您也可以这样做:
SELECT count(*) AS total
, sum(myCol) AS countTrue --yes, you can add TRUEs as TRUE=1 and FALSE=0 !!
FROM yourTable
;
我认为在 Postgres 中,这是可行的:
SELECT count(*) AS total
, sum(myCol::int) AS countTrue --convert Boolean to Integer
FROM yourTable
;
或更好(避免 :: 并使用标准 SQL 语法):
SELECT count(*) AS total
, sum(CAST(myCol AS int)) AS countTrue --convert Boolean to Integer
FROM yourTable
;
【讨论】:
这是我见过的最简单的解决方案^_^【参考方案8】:只需将布尔字段转换为整数并求和。这将适用于 postgresql:
select sum(myCol::int) from <table name>
希望有帮助!
【讨论】:
它并不比其他解决方案更快也更精确。我相信您来自 Oracle,因为使用 int 作为布尔值对您来说更直观。【参考方案9】:SELECT count(*) -- or count(myCol)
FROM <table name> -- replace <table name> with your table
WHERE myCol = true;
这是一种使用窗口函数的方法:
SELECT DISTINCT *, count(*) over(partition by myCol)
FROM <table name>;
-- Outputs:
-- --------------
-- myCol | count
-- ------+-------
-- f | 2
-- t | 3
-- | 1
【讨论】:
抱歉,我无法为应用此解决方案的更复杂示例返回多行。 是的,但您可以通过添加WHERE myCol = true
来进一步限制它。我提供第二个示例不是因为它更快,而是更多地作为 Postgres 窗口函数的教育部分,许多用户对此感到不满意或不知道。【参考方案10】:
基准测试
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
实际基准
在 1.4GHz i5 MacBookPro、psql 和 pg 12.4(Linux docker 容器中的 pg)上制作:
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
【讨论】:
【参考方案11】:select count(myCol)
from mytable
group by myCol
;
将 bool 的 3 种可能状态 (false, true, 0) 分组为三行 与另一列(如 day)组合在一起时特别方便
【讨论】:
以上是关于postgresql - sql - `true` 值的计数的主要内容,如果未能解决你的问题,请参考以下文章