我在count(*)
和join
周围遇到了微妙之处,希望能得到一些确认,我已经弄清楚了正在发生的事情。对于背景,我们通常将连续的时间轴数据转换为离散的bin,例如小时。而且,由于我们不希望没有内容的垃圾箱出现间隙,因此我们将使用generate_series
来合成我们想要的值的存储桶。如果没有输入,例如10AM,很好,我们直到结果。但是,我注意到有时会得到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.
似乎就是这样,您必须明确指出要对数据表进行计数。否则,由于系列数据is匹配一次,您将获得1的计数。这是联接的细微差别,还是Postgres中count
的细微差别?
这是否会影响其他汇总?似乎没有。
P.S。 generate_series
几乎是有史以来最好的事情。
您已正确解决问题:根据给定的参数,count()
的行为有所不同。
count(*)
计算属于该组的行数。只是不能为0
,因为一个组中总是至少有一行(否则,就没有一个组)。
另一方面,当给定列名或表达式作为参数时,count()
考虑任何非null
值,而忽略null
值。对于您的查询,这使您可以将left join
ed表中不匹配的组与存在匹配项的组区分开。