[英]SUM For Distinct Rows
給定以下表結構:
countries: id, name
regions: id, country_id, name, population
cities: id, region_id, name
...以及此查詢...
SELECT c.name AS country, COUNT(DISTINCT r.id) AS regions, COUNT(s.id) AS cities
FROM countries AS c
JOIN regions AS r ON r.country_id = c.id
JOIN cities AS s ON s.region_id = r.id
GROUP BY c.id
如何添加regions.population
值的SUM
以計算該國的人口? 求和時,我只需要使用每個區域的值一次,但是未分組的結果將為每個區域(該區域中的城市數)顯示多行。
示例數據:
mysql> SELECT * FROM countries;
+----+-----------+
| id | name |
+----+-----------+
| 1 | country 1 |
| 2 | country 2 |
+----+-----------+
2 rows in set (0.00 sec)
mysql> SELECT * FROM regions;
+----+------------+-----------------------+------------+
| id | country_id | name | population |
+----+------------+-----------------------+------------+
| 11 | 1 | region 1 in country 1 | 10 |
| 12 | 1 | region 2 in country 1 | 15 |
| 21 | 2 | region 1 in country 2 | 25 |
+----+------------+-----------------------+------------+
3 rows in set (0.00 sec)
mysql> SELECT * FROM cities;
+-----+-----------+---------------------------------+
| id | region_id | name |
+-----+-----------+---------------------------------+
| 111 | 11 | City 1 in region 1 in country 1 |
| 112 | 11 | City 2 in region 1 in country 1 |
| 121 | 12 | City 1 in region 2 in country 1 |
| 211 | 21 | City 1 in region 1 in country 2 |
+-----+-----------+---------------------------------+
4 rows in set (0.00 sec)
所需的輸出和示例數據:
+-----------+---------+--------+------------+
| country | regions | cities | population |
+-----------+---------+--------+------------+
| country 1 | 2 | 3 | 25 |
| country 2 | 1 | 1 | 25 |
+-----------+---------+--------+------------+
我更喜歡不需要更改JOIN
邏輯的解決方案。
這篇文章 可接受的解決方案似乎與我正在尋找的解決方案差不多,但是我還無法弄清楚如何將其應用於我的問題。
我的解決方案
SELECT c.id AS country_id,
c.name AS country,
COUNT(x.region_id) AS regions,
SUM(x.population) AS population,
SUM(x.cities) AS cities
FROM countries AS c
LEFT JOIN (
SELECT r.country_id,
r.id AS region_id,
r.population AS population,
COUNT(s.id) AS cities
FROM regions AS r
LEFT JOIN cities AS s ON s.region_id = r.id
GROUP BY r.country_id, r.id, r.population
) AS x ON x.country_id = c.id
GROUP BY c.id, c.name
注意: 我的實際查詢要復雜得多,與國家,地區或城市無關。 這是一個最小的例子來說明我的問題。
首先,您引用的其他帖子情況不一樣。 在這種情況下,連接就像[A-> B和A-> C],因此加權平均值(該計算所執行的操作)是正確的。 在您的情況下,聯接就像[A-> B-> C],因此您需要一種不同的方法。
立即想到的最簡單的解決方案確實涉及一個子查詢,但並不復雜:
SELECT
c.name AS country,
COUNT(r.id) AS regions,
SUM(s.city_count) AS cities,
SUM(r.population) as population
FROM countries AS c
JOIN regions AS r ON r.country_id = c.id
JOIN
(select region_id, count(*) as city_count
from cities
group by region_id) AS s
ON s.region_id = r.id
GROUP BY c.id
這樣做的原因是,在加入該區域之前將城市解析為每個區域一行,從而消除了交叉連接的情況。
離開剩下的,再增加一個加入人群的怎么樣
SELECT c.name AS country,
COUNT(distinct r.id) AS regions,
COUNT(s.id) AS cities,
pop_regs.sum as total_population
FROM countries AS c
LEFT JOIN regions AS r ON r.country_id = c.id
LEFT JOIN cities AS s ON s.region_id = r.id
left join
(
select country_id, sum(population) as sum
from regions
group by country_id
) pop_regs on pop_regs.country_id = c.id
GROUP BY c.id, c.name
首先,您應該知道問題中提到的問題及其解決方案與問題及其解決方案稍有不同。 因此,沒有子查詢就不能只使用JOIN
。
桌子:
國家:
===========================
| id | name |
===========================
| 1 | country 1 |
---------------------------
| 2 | country 2 |
---------------------------
| 3 | country 3 |
---------------------------
| 4 | country 4 |
---------------------------
地區:
=============================================
| id |country_id| name |population|
=============================================
| 1 | 1 | c1 - r1 | 10 |
---------------------------------------------
| 2 | 1 | c1 - r2 | 15 |
---------------------------------------------
| 3 | 1 | c1 - r3 | 15 |
---------------------------------------------
| 4 | 2 | c2 - r1 | 25 |
---------------------------------------------
| 5 | 3 | c3 - r1 | 13 |
---------------------------------------------
城市:
========================================
| id | region_id | name |
========================================
| 1 | 1 | city 1 |
----------------------------------------
| 2 | 1 | city 2 |
----------------------------------------
| 3 | 2 | city 3 |
----------------------------------------
| 4 | 2 | city 4 |
----------------------------------------
| 5 | 2 | city 5 |
----------------------------------------
| 6 | 3 | city 6 |
----------------------------------------
| 7 | 3 | city 7 |
----------------------------------------
| 8 | 4 | city 8 |
----------------------------------------
| 9 | 4 | city 9 |
----------------------------------------
| 10 | 4 | city 10 |
----------------------------------------
作為一個簡單的方法,你可以加入countries
表與子查詢聯接regions
和cities
的表拿到2個表: countries
和regions
與cities
列:
SQL:
SELECT
r.id AS id,
r.country_id AS country_id,
r.name AS name,
r.population AS population,
COUNT(s.region_id) AS cities
FROM regions r
/* we use left joint and not only join to get also regions without cities */
LEFT JOIN cities s
ON r.id = s.region_id
GROUP BY r.id
資料:
==================================================================
| id | country_id | name | population | cities |
==================================================================
| 1 | 1 | c1 - r1 | 10 | 2 |
------------------------------------------------------------------
| 2 | 1 | c1 - r2 | 15 | 3 |
------------------------------------------------------------------
| 3 | 1 | c1 - r3 | 15 | 2 |
------------------------------------------------------------------
| 4 | 2 | c2 - r1 | 25 | 3 |
------------------------------------------------------------------
| 5 | 3 | c3 - r1 | 13 | 0 |
------------------------------------------------------------------
然后,您必須執行常規命令,才能得到以下代碼:
SQL:
SELECT
c.name AS country,
COUNT(r.country_id) AS regions,
/* ifnull is used here to show 0 instead of null */
SUM(IFNULL(r.cities, 0)) AS cities,
SUM(IFNULL(r.population, 0)) AS population
FROM countries c
/* we use left joint and not only join to get also countries without regions */
LEFT JOIN (
SELECT
/* we don't need regions.id and regions.name */
r.country_id AS country_id,
r.population AS population,
COUNT(s.region_id) AS cities
FROM regions r
LEFT JOIN cities s
ON r.id = s.region_id
GROUP BY r.id
) r
ON c.id = r.country_id
GROUP BY c.id
結果如下:
=====================================================
| country | regions | cities | population |
=====================================================
| country 1 | 3 | 7 | 40 |
-----------------------------------------------------
| country 2 | 1 | 3 | 25 |
-----------------------------------------------------
| country 3 | 1 | 0 | 13 |
-----------------------------------------------------
| country 4 | 0 | 0 | 0 |
-----------------------------------------------------
相比之下,僅使用JOIN
會刪除沒有地區的國家和帶有沒有城市的地區的國家:
=====================================================
| country | regions | cities | population |
=====================================================
| country 1 | 3 | 7 | 40 |
-----------------------------------------------------
| country 2 | 1 | 3 | 25 |
-----------------------------------------------------
對於您的確切示例(問題中提到的數據),您將獲得:
=====================================================
| country | regions | cities | population |
=====================================================
| country 1 | 2 | 3 | 25 |
-----------------------------------------------------
| country 2 | 1 | 1 | 25 |
-----------------------------------------------------
希望所有這些都可以幫助您獲得想要的東西。
使用LEFT OUTER JOIN而不是INNER JOIN,因為如果國家/地區沒有區域,那么如果您使用INNER JOIN ,則該國家/地區不會進入結果,如果同一地區如果沒有城市,那么該國家/地區將不計入結果。
因此,請使用LEFT OUTER JOIN代替INNER JOIN或JOIN 。
嘗試這個:
SELECT c.name AS country, r.regions, r.population, r.cities
FROM countries AS c
LEFT OUTER JOIN (SELECT r.country_id,
COUNT(r.id) AS regions,
SUM(r.population) AS population,
SUM(c.cities) AS cities
FROM regions AS r
LEFT OUTER JOIN (SELECT c.region_id, COUNT(c.id) AS cities
FROM cities AS C
GROUP BY c.region_id
) AS c ON r.id = c.region_id
GROUP BY r.country_id
) AS r ON c.id = r.country_id;
輸出值
| COUNTRY | REGIONS | POPULATION | CITIES |
|---------|---------|------------|--------|
| usa | 3 | 16 | 4 |
| germany | 2 | 5 | 1 |
我在SQL中使用此查詢測試了您在下面提供的同一表
select regioncount.name as country,regioncount.regions, citycount.cities,regioncount.population from
(SELECT c.name,c.id,COUNT(r.id) AS regions ,SUM(r.population) as population
FROM countries AS c
JOIN regions AS r on c.id = r.country_id GROUP BY c.id,c.name) as regioncount
join
(SELECT
r.country_id,
COUNT(s.id) AS cities
FROM regions AS r
JOIN cities AS s on r.id =s.region_id GROUP BY r.country_id) as citycount on citycount.country_id = regioncount.id
我得到了你想要的結果
+-----------+---------+--------+------------+
| country | regions | cities | population |
+-----------+---------+--------+------------+
| country 1 | 2 | 3 | 25 |
| country 2 | 1 | 1 | 25 |
+-----------+---------+--------+------------+
如果您不想引入/更改JOIN
或SUBQUERY
,則這是另一種方法
SELECT
c.name AS country,
COUNT(distinct r.id) AS regions,
COUNT(s.id) AS cities,
SUM(DISTINCT(((((r.id*r.id) + (r.population*r.id)))-(r.id*r.id))/r.id)) as total_population
FROM
countries AS c
JOIN regions AS r ON r.country_id = c.id
LEFT JOIN cities AS s ON s.region_id = r.id
GROUP
BY c.id
您的問題很普遍。 您將所有與要查看的數據有關的表聯接在一起,然后開始考慮如何獲取該數據。 當您遇到不同的聚合時,這並不容易實現。
因此,最好加入您實際感興趣的內容。在您的情況下:國家和每個國家(總計)的地區/城市數據。 這樣可以使查詢簡單明了且易於維護。
select
c.name as country,
r.regions,
r.population,
r.cities
from countries as c
join
(
select
country_id,
count(*) as regions,
sum(population) as population,
sum((select count(*) from cities where cities.region_id = regions.id)) as cities
from regions
group by country_id
) as r on r.country_id = c.id;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.