从具有条件的多个表中按计数分组

Group By Count from Multiple Tables with conditions

我有 3 个不同的 table,国家、城市和客户。表格如下:

国家table:

id   country_name
1    UK
2    US
3   Brazil
:    
n   Canada

城市table

id  city_name  postal_code  country_id
1    London        30090         1
2    Dallas        20909         2
3    Rio           29090         3
4    Atlanta       30318         2
:
n    Vancouver     32230         n

顾客table

id    customer_name     city_id
1        John             1
2        Pete             3
3        Dave             2
4        May              2
5        Chuck            4
6        Sam              3
7        Henry            3

***country.id 是引用 city.country_id,city.id 是引用 customer.city_id

我想写一个查询,可以提取国家名称、城市名称和相关城市的客户数量。但是在一个条件下,查询将 return 所有城市的客户数量超过所有城市的平均客户数量

它看起来像下面这样,这是正确的输出

UK London 2
Brazil Rio 3

但我一直得到这个输出,这是不正确的

UK London 2
US Dallas 2
US Atlanta 1
Brazil Rio 3

我写了一个 SQL 查询,但它没有给我想要的结果

SELECT country.country_name, city.city_name, COUNT(customer.city_id) from country 
JOIN city on country.id = city.country_id 
JOIN customer on city.id = customer.city_id
Group by city_name,country.country_name;

我想知道如何执行此操作并修复我的代码?

您需要将查询嵌套到子查询中,以便您可以取计数的平均值并将当前计数与其进行比较。如果您使用的是支持 CTE 的 SQL,您可以使用一个

WITH cnts AS (
  SELECT country.country_name, city.city_name, COUNT(customer.city_id) AS cnt 
  FROM country 
  JOIN city on country.id = city.country_id 
  JOIN customer on city.id = customer.city_id
  GROUP BY city_name,country.country_name
)
SELECT *
FROM cnts
WHERE cnt > (SELECT AVG(cnt) FROM cnts)

否则查询会变得更加复杂,主查询也需要作为 WHERE 子句中的子查询:

SELECT country.country_name, city.city_name, COUNT(customer.city_id) AS cnt 
FROM country 
JOIN city on country.id = city.country_id 
JOIN customer on city.id = customer.city_id
GROUP BY city_name,country.country_name
HAVING COUNT(customer.city_id) > (SELECT AVG(cnt) FROM (
  SELECT country.country_name, city.city_name, COUNT(customer.city_id) AS cnt 
  FROM country 
  JOIN city on country.id = city.country_id 
  JOIN customer on city.id = customer.city_id
  GROUP BY city_name,country.country_name
) cnts2)

在这两种情况下,样本数据的输出都是:

country_name    city_name   cnt
Brazil          Rio         3
US              Dallas      2

Demo on dbfiddle

您可以使用 window 函数:

SELECT cc.*
FROM (SELECT co.country_name, ci.city_name, COUNT(*) AS cnt,
             AVG(COUNT(*)) OVER () as avg_count
      FROM country co JOIn
           city ci
           ON co.id = ci.country_id JOIN 
           customer cu
           ON ci.id = cu.city_id
      GROUP BY ci.city_name, co.country_name
     ) cc
WHERE cnt > avg_count;