在 MySQL 中使用 SUM 聚合連接表:解決交叉產品問題
在 MySQL 中,使用 SUM 聚合函數組合兩個查詢通常會帶來挑戰。表之間的交叉乘積可能導致 SUM 值不正確。為了解決這個問題,需要將 SUM 函數封裝到子查詢中。
考慮以下範例,其中兩個查詢分別針對特定日期和教師 ID 為 5 的情況檢索 SUM(drive_time) 和 SUM(tm_hours):
查詢 1:
<code class="language-sql">SELECT last_name, first_name, DATE_FORMAT(mil_date, '%m/%d/%y') AS dates, SUM(drive_time) MINUTES FROM bhds_mileage LEFT JOIN bhds_teachers i ON i.ds_id = bhds_mileage.ds_id WHERE mil_date BETWEEN '2016-04-11' AND '2016-04-30' AND bhds_mileage.ds_id = 5 GROUP BY CONCAT(YEAR(mil_date), '/', WEEK(mil_date)), bhds_mileage.ds_id ORDER BY last_name ASC, dates ASC</code>
查詢 2:
<code class="language-sql">SELECT last_name, first_name, DATE_FORMAT(tm_date, '%m/%d/%y') AS dates, SUM(tm_hours) total FROM bhds_timecard LEFT JOIN bhds_teachers i ON i.ds_id = bhds_timecard.ds_id WHERE tm_date BETWEEN '2016-04-11' AND '2016-04-30' AND bhds_timecard.ds_id = 5 GROUP BY CONCAT(YEAR(tm_date), '/', WEEK(tm_date)), bhds_timecard.ds_id ORDER BY last_name ASC, dates ASC</code>
簡單的連線嘗試:
要組合這些查詢,一個簡單的方法是將它們連接如下:
<code class="language-sql">SELECT last_name, first_name, DATE_FORMAT(tm_date, '%m/%d/%y') AS dates, SUM(tm_hours) total, SUM(drive_time) MINUTES FROM bhds_timecard LEFT JOIN bhds_teachers i ON i.ds_id = bhds_timecard.ds_id LEFT JOIN bhds_mileage ON DATE_FORMAT(bhds_timecard.tm_date, '%m/%d/%y') = DATE_FORMAT(bhds_mileage.mil_date, '%m/%d/%y') AND bhds_timecard.ds_id = bhds_mileage.ds_id WHERE tm_date BETWEEN '2016-04-11' AND '2016-04-30' AND bhds_timecard.ds_id = 5 GROUP BY CONCAT(YEAR(tm_date), '/', WEEK(tm_date)), bhds_timecard.ds_id </code>
但是,這種方法會在表格之間建立交叉乘積,導致 SUM 值不正確。
解:
為了得到正確的 SUM 值,將 SUM 聚合函數移到子查詢中。這可以防止交叉乘積問題,並確保僅在相關行中計算 SUM 值:
<code class="language-sql">SELECT last_name, first_name, DATE_FORMAT(LEAST(mil_date, tm_date), '%m/%d/%y') AS dates, total, minutes FROM bhds_teachers AS i LEFT JOIN ( SELECT ds_id, YEARWEEK(mil_date) AS week, MIN(mil_date) AS mil_date, SUM(drive_time) AS minutes FROM bhds_mileage WHERE mil_date BETWEEN '2016-04-11' AND '2016-04-30' AND bhds_mileage.ds_id = 5 GROUP BY ds_id, week ) AS m ON m.ds_id = i.ds_id LEFT JOIN ( SELECT ds_id, YEARWEEK(tm_date) AS week, MIN(tm_date) AS tm_date, SUM(tm_hours) AS total FROM bhds_timecard WHERE tm_date BETWEEN '2016-04-11' AND '2016-04-30' AND bhds_timecard.ds_id = 5 GROUP BY ds_id, week ) AS t ON t.ds_id = i.ds_id AND t.week = m.week </code>
以上是如何正確對 MySQL 中連接表的聚合值求和以避免交叉乘積問題?的詳細內容。更多資訊請關注PHP中文網其他相關文章!