簡體   English   中英

Mysql - 按其他列值求和

[英]Mysql - Sum by other column value

這就是問題所在。 我有一個很長但不是很復雜的查詢:

SUM(x.value)
FROM valuetable AS x
LEFT JOIN jointable_1 AS y
LEFT JOIN jointable_2 AS z
etc
...
GROUP BY y.id, z.id

有 n 個左連接,我需要保持這種方式,因為新的左連接必須隨時可用。 我顯然將 n 值復制到 SUM 中,因為joinables 可以有多個結果,並且出於靈活的 WHERE 原因,我不能將它們中的任何一個分解為子查詢。 我只需要每個 x.id 一個 x.value 到 SUM 中,這也很明顯。

- 我不能將 x.id 添加到 GROUP BY,因為我需要一行來為每個 y.id 求和。

- 我不能使用計算:

SUM(x.value)*COUNT(DISTINCT x.id)/COUNT(*)

因為總和可以有任意數量的 x.values,因為不同的 x.id-s 有不同數量的連接。

- 我不能選擇 DISTINCT x.value,因為任何 x.id 都可以有任何 x.value 並且它們可以包含相同的值。

- 我不知道如何為 sum 創建子查詢,因為我不能在子查詢中使用聚合值(例如 GROUP_CONCAT(DISTINCT x.id)),或者我可以嗎?

無論如何,就是這樣。 我知道我可以重新排列查詢(子查詢而不是連接,不同於),但我想把它作為最后的手段。 有沒有辦法實現我想要的?

很抱歉,沒有子查詢(或視圖),沒有通用的方法可以做你想做的事。

一點行話:“基數”。 對於我們的目的,它是表或結果集中的行數。 (就我們而言,結果集是一種虛擬表。)

對於像SUM(col)COUNT(*)這樣的聚合函數要給出好的結果,我們必須注意被匯總表的基數。 這種事

  SELECT DATE(sale_time) sale_date, 
         store_id,
         SUM(sale_amount) total_sales
    FROM sale
   GROUP BY DATE(sale_time), store_id

總結與基礎表相同的結果表基數,因此它生成有用的結果。

但是,如果我們這樣做

  SELECT DATE(sale.sale_time) sale_date, 
         sale.store_id,
         SUM(sale.sale_amount) total_sales,
         COUNT(promo.promo_id) promos
    FROM sale
    LEFT JOIN promo ON sale.store_id = promo.store_id 
                   AND DATE(sale.sale_time) = promo.promo_date
   GROUP BY DATE(sale.sale_time), sale.store_id

我們破壞了匯總結果集的基數。 除非我們確定每個商店在每一天都有零個或一個促銷記錄,否則這永遠不會起作用。 為什么不? LEFT JOIN 操作會影響正在匯總的虛擬表的基數。 這意味着一些 sale_amount 值我不止一次出現在 SUM 中,因此 SUM 將不正確或不值得信賴。

如何防止 LEFT JOIN 操作弄亂您的基數? 確保您的 LEFT JOIN 的ON子句將右側的每一行與左側的零行或一行相匹配。 也就是說,確保 JOIN 兩側的(虛擬)表具有適當的基數。

(在實體關系行話中,您的 SUM 失敗,因為您在進行求和之前加入了具有一對多關系的兩個實體。)

理論上最簡潔的方法是在連接之前執行兩個聚合操作。 這以 LEFT JOIN 是一對無或一對一的方式連接兩個虛擬表

  SELECT sales.sale_date, 
         sales.store_id,
         sales.total_sales,
         promos.promo_count
    FROM (
            SELECT DATE(sale_time) sale_date, 
                   store_id,
                   SUM(sale_amount) total_sales
              FROM sale
          GROUP BY DATE(sale_time), sale_store
         ) sales
    LEFT JOIN (
            SELECT store_id,
                   promo_date
                   COUNT(*) promo_count
              FROM promo
             GROUP BY store_id, promo_date 
         ) promos ON sales.store_id = promos.store_id
                 AND sales.sale_date = promo.promo_date

盡管此 SQL 很復雜,但大多數服務器都能有效地處理這種模式。

故障排除提示:如果您在查詢的同一級別看到SUM() ... FROM ... JOIN ... GROUP BY ,則可能存在基數問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM