假设我有一个包含城市及其人口的表和一个包含不同类型建筑物的表。我想知道居住在有学校的城市的人口百分比。
城市:
名字 | 流行 |
---|---|
A | 10 |
B | 100 |
C | 1000 |
建筑物:
是_学校 | 城市 |
---|---|
假 | A |
真实 | B |
真实 | B |
真实 | C |
如果我做这样的事情:
SELECT
SUM(CASE WHEN building.is_school = true THEN city.pop ELSE 0 END) school,
SUM(city.pop) total
FROM city
LEFT JOIN building ON building.city = city.name;
我将 B 城市人口加起来两次。 我想要:
学校 | 总计 |
---|---|
1100 | 1110 |
但我得到:
学校 | 总计 |
---|---|
1200 | 1210 |
我可以做一个子查询:
SELECT
SUM(CASE WHEN city.name in (
SELECT city.name
FROM city
LEFT JOIN building ON building.city = city.name
WHERE building.is_school = true
) THEN city.pop ELSE 0 END),
SUM(city.pop)
FROM city;
但考虑到我想要实现的目标,感觉没有必要复杂,真的没有其他方法吗?
你可以这样做:
SELECT
1.0 * sum(case when exists (
select 1 from building b where b.city = c.name and is_school) then 1 else 0 end)
/ count(*)
FROM city c;
结果:
?column?
--------
0.66666666666666666667
请参阅 db<>fiddle 处的运行示例。
您可以使用的另一种方法是加入建筑物的过滤版本而不是建筑物本身
SELECT
SUM(CASE WHEN building.is_school = true THEN city.pop ELSE 0 END) school, SUM(city.pop) total
FROM city
LEFT JOIN (SELECT DISTINCT city, is_school FROM building) building ON building.city = city.name;
对于庞大的数据库,不建议使用DISTINCT,因为确定不同记录的过程非常慢,但至少查询是苗条可爱的