仅使用外部连接计数 returns 个计数不为零的数据
Counting with outer joins only returns data from which count is not zero
假设我有两个 table:user
和 diary
。
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;
不需要子查询。
假设我有两个 table:user
和 diary
。
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;
不需要子查询。