仅使用外部连接计数 returns 个计数不为零的数据

Counting with outer joins only returns data from which count is not zero

假设我有两个 table:userdiary

select count(id)
from user
where is_tester is false

这里的主键总是被称为id。上面的这个查询给了我大约 270000,这意味着我有大约 270000 个用户。现在我想知道每个用户有多少日记。所以我去了:

select u.id as user_id, u.dm_type, count(d.id) as bg_count
from diary as d
right join (
    select id, dm_type
    from user
    where is_tester is false
) as u
on d.user_id = u.id
where d.glucose_value > 0
group by u.id, u.dm_type

每个用户只能拥有一种dm_type。我期待它会告诉我每个用户有多少日记,如果没有任何日记,它会给我一个 NA 或 0,因为我使用 right join。但是,返回的 table 只有大约 75000 行,并且 table 中的每个用户至少有一本日记。那不是我想要的。为什么会发生,我应该如何正确处理?

我参考了Combining RIGHT JOIN with COUNT,并根据已接受答案的建议计算了一个特定字段。


根据评论编辑:

user:

| id | dm_type | is_tester |
|----|---------|-----------|
| 1  | 1       | False     |
| 2  | 1       | False     |
| 3  | 2       | False     |
| 4  | no      | False     |
| 5  | 2       | True      |

diary:

| id | user_id | glucose_value |
|----|---------|---------------|
| 1  | 1       | -2            |
| 2  | 1       | 80            |
| 3  | 2       | 78            |
| 4  | 2       | 100           |
| 5  | 4       | 83            |
| 6  | 5       | 90            |

预期结果:

| user_id | dm_type | bg_count |
|---------|---------|----------|
| 1       | 1       | 1        |
| 2       | 1       | 2        |
| 3       | 2       | 0        |
| 4       | no      | 1        |

尝试左连接,它会给你所有用户是否有日记计数 如果任何用户没有日记那么它会给你 null

select u.id as user_id, u.dm_type, count(d.id) as bg_count from
(select id, dm_type from user where is_tester is false)u
left join diary d on d.user_id = u.id and d.glucose_value > 0
group by u.id, u.dm_type

您的查询的问题是 where 子句。它正在从外部连接中过滤掉不匹配的日记。

当您处理此类问题时,我强烈建议 left join 而不是 right join。意思是"keep all the rows in the first table even if nothing matches in the second"。这通常比 "keep all the rows in whatever table is at the end of the from clause but I haven't seen yet".

更容易理解

下一个规则是 first table 的条件进入 where 子句,因为它们确实过滤行。第二个 table 的条件进入 on 子句。它们不过滤行,但用于匹配。

因此,您可以将查询表述为:

select u.id as user_id, u.dm_type, count(d.id) as bg_count
from user u left join
     diary d
     on d.user_id = u.id and d.glucose_value > 0
where u.is_tester is false
group by u.id, u.dm_type;

不需要子查询。