我遇到了一个微妙的问题 count(*)
以及 join
,希望得到一些确认,我已经正确地知道发生了什么。在后台,我们通常将连续的时间线数据转换为离散的时间段,例如小时。既然我们不希望没有内容的垃圾箱有空隙,我们就用 generate_series
合成我们想要的桶值。如果上午10点没人报名,好吧,我们还是会有结果的。但是,我注意到有时我得到的是1而不是0。我想确认的是:
如果对“网格”系列进行计数,则计数为1;如果对数据表进行计数,则计数为0。
这只与 count
,无其他骨料。
下面的代码设置了一些示例数据来显示我所说的内容:
DROP TABLE IF EXISTS analytics.measurement_table CASCADE;
CREATE TABLE IF NOT EXISTS analytics.measurement_table (
hour smallint NOT NULL DEFAULT NULL,
measurement smallint NOT NULL DEFAULT NULL
);
INSERT INTO measurement_table (hour, measurement)
VALUES ( 0, 1),
( 1, 1), ( 1, 1),
(10, 2), (10, 3), (10, 5);
以下是查询的目标结果。我用了12个小时来缩短示例结果。
Hour Count sum
0 1 1
1 2 2
2 0 0
3 0 0
4 0 0
5 0 0
6 0 0
7 0 0
8 0 0
9 0 0
10 3 10
11 0 0
12 0 0
这可以正常工作:
WITH hour_series AS (
select * from generate_series (0,12) AS hour
)
SELECT hour_series.hour,
count(measurement_table.hour) AS frequency,
COALESCE(sum(measurement_table.measurement), 0) AS total
FROM hour_series
LEFT JOIN measurement_table ON (measurement_table.hour = hour_series.hour)
GROUP BY 1
ORDER BY 1
这将在匹配中返回1:
WITH hour_series AS (
select * from generate_series (0,12) AS hour
)
SELECT hour_series.hour,
count(*) AS frequency,
COALESCE(sum(measurement_table.measurement), 0) AS total
FROM hour_series
LEFT JOIN measurement_table ON (hour_series.hour = measurement_table.hour)
GROUP BY 1
ORDER BY 1
0 1 1
1 2 2
2 1 0
3 1 0
4 1 0
5 1 0
6 1 0
7 1 0
8 1 0
9 1 0
10 3 10
11 1 0
12 1 0
这两个例子之间的唯一区别是 count
期限:
count(*) -- A result of 1 on no match, and a correct count otherwise.
count(joined to table field) -- 0 on no match, correct count otherwise.
似乎就是这样,你必须明确你在数数据表。否则,由于序列数据只匹配一次,因此计数为1。这是联合的细微差别,还是 count
在博士后?
这会影响到其他的争吵吗?好像不应该。
附笔 generate_series
是有史以来最好的事情。
1条答案
按热度按时间pxy2qtax1#
你正确地解决了问题:
count()
根据给定的参数,行为会有所不同。count(*)
统计属于组的行数。这是不可能的0
因为一个组中总是至少有一行(否则就没有组)。另一方面,当给定列名或表达式作为参数时,
count()
考虑到任何非-null
值,并忽略null
价值观。对于您的查询,这允许您区分组中没有匹配项的组left join
从有匹配项的组中删除表。请注意,此行为不是特定于postgres的,而是属于标准ansisql规范(我知道的所有数据库都符合该规范)。
底线:
一般情况下,使用
count(*)
; 这样效率更高,因为数据库不需要检查null
s(并向查询的读者说明您只想知道有多少行属于该组)在像你这样的特殊情况下,请在
count()