2014-09-19 18 views
1

我正在努力實現的目標:在給定日期內按數量和金額滾動總額,按小時分組。滾動總計,沒有子選擇和沒有供應商特定的擴展

在大多數情況下很容易,但是如果你有一些額外的列(在我的情況下目錄和產品),你不想對它們進行分組/過濾,這是一個問題。

我知道在Oracle和MSSQL中有專門的擴展,Postgres中有SELECT OVER PARTITION。 目前我正在開發一個應用程序原型,它由MySQL支持,我不知道它將在生產環境中使用什麼,所以我試圖避免供應商鎖定。

的entrire表:

> SELECT id, dir, product, date, hour, quantity, amount FROM sales 
    ORDER BY date, hour; 

+------+-----+---------+------------+------+----------+--------+ 
| id | dir | product | date  | hour | quantity | amount | 
+------+-----+---------+------------+------+----------+--------+ 
| 2230 | 65 | ABCDEDF | 2014-09-11 | 1 |  1 |  10 | 
| 2231 | 64 | ABCDEDF | 2014-09-11 | 3 |  4 |  40 | 
| 2232 | 64 | ABCDEDF | 2014-09-11 | 5 |  5 |  50 | 
| 2235 | 64 | ZZ  | 2014-09-11 | 7 |  6 |  60 | 
| 2233 | 64 | ABCDEDF | 2014-09-11 | 7 |  6 |  60 | 
| 2237 | 66 | ABCDEDF | 2014-09-11 | 7 |  6 |  60 | 
| 2234 | 64 | ZZ  | 2014-09-18 | 3 |  1 |  11 | 
| 2236 | 66 | ABCDEDF | 2014-09-18 | 3 |  1 | 100 | 
| 2227 | 64 | ABCDEDF | 2014-09-18 | 3 |  1 | 100 | 
| 2228 | 64 | ABCDEDF | 2014-09-18 | 5 |  2 | 200 | 
| 2229 | 64 | ABCDEDF | 2014-09-18 | 7 |  3 | 300 | 
+------+-----+---------+------------+------+----------+--------+ 

對於給定的日期:

> SELECT id, dir, product, date, hour, quantity, amount FROM sales 
    WHERE date = '2014-09-18' 
    ORDER BY hour; 

+------+-----+---------+------------+------+----------+--------+ 
| id | dir | product | date  | hour | quantity | amount | 
+------+-----+---------+------------+------+----------+--------+ 
| 2227 | 64 | ABCDEDF | 2014-09-18 | 3 |  1 | 100 | 
| 2236 | 66 | ABCDEDF | 2014-09-18 | 3 |  1 | 100 | 
| 2234 | 64 | ZZ  | 2014-09-18 | 3 |  1 |  11 | 
| 2228 | 64 | ABCDEDF | 2014-09-18 | 5 |  2 | 200 | 
| 2229 | 64 | ABCDEDF | 2014-09-18 | 7 |  3 | 300 | 
+------+-----+---------+------------+------+----------+--------+ 

,我需要的結果,使用子選擇:

> SELECT date, hour, SUM(quantity), 
    (SELECT SUM(quantity) FROM sales s2 
    WHERE s2.hour <= s1.hour AND s2.date = s1.date 
) AS total 
    FROM sales s1 
    WHERE s1.date = '2014-09-18' 
    GROUP by date, hour; 

+------------+------+---------------+-------+ 
| date  | hour | sum(quantity) | total | 
+------------+------+---------------+-------+ 
| 2014-09-18 | 3 |    3 |  3 | 
| 2014-09-18 | 5 |    2 |  5 | 
| 2014-09-18 | 7 |    3 |  8 | 
+------------+------+---------------+-------+ 

我使用子擔憂 - 請選擇:

  1. 一旦表中有一百萬條記錄,查詢可能會變得太慢,不知道它是否需要優化,即使它沒有HAVING語句。

  2. 如果我不得不在productdir過濾,我將不得不把這些條件都主SELECT和子SELECT太(WHERE product =/WHERE dir =)。

  3. 子選擇只計算單個總數,而我需要其中兩個(sum(quantity)sum(amount))(ERROR 1241 (21000): Operand should contain 1 column(s))。

最接近的結果我都能夠使用JOIN獲得:

> SELECT DISTINCT(s1.hour) AS ih, s2.date, s2.hour, s2.quantity, s2.amount, s2.id 
    FROM sales s1 
    JOIN sales s2 ON s2.date = s1.date AND s2.hour <= s1.hour 
    WHERE s1.date = '2014-09-18' 
    ORDER by ih; 

+----+------------+------+----------+--------+------+ 
| ih | date  | hour | quantity | amount | id | 
+----+------------+------+----------+--------+------+ 
| 3 | 2014-09-18 | 3 |  1 | 100 | 2236 | 
| 3 | 2014-09-18 | 3 |  1 | 100 | 2227 | 
| 3 | 2014-09-18 | 3 |  1 |  11 | 2234 | 
| 5 | 2014-09-18 | 3 |  1 | 100 | 2236 | 
| 5 | 2014-09-18 | 3 |  1 | 100 | 2227 | 
| 5 | 2014-09-18 | 5 |  2 | 200 | 2228 | 
| 5 | 2014-09-18 | 3 |  1 |  11 | 2234 | 
| 7 | 2014-09-18 | 3 |  1 | 100 | 2236 | 
| 7 | 2014-09-18 | 3 |  1 | 100 | 2227 | 
| 7 | 2014-09-18 | 5 |  2 | 200 | 2228 | 
| 7 | 2014-09-18 | 7 |  3 | 300 | 2229 | 
| 7 | 2014-09-18 | 3 |  1 |  11 | 2234 | 
+----+------------+------+----------+--------+------+ 

我可以停在這裏只是IH(小時)使用這些結果進行分組,計算總和數量和金額和要開心。但是有些東西讓我誤以爲這是錯誤的。

如果我刪除DISTINCT,大部分行將變得重複。用它的不變式替換JOIN並不會幫助。

有一次,我從聲明中刪除s2.id你得到一個完整的混亂與消失/坍塌有意義行(如IDS二千二百二十七分之二千二百三十六得到了摺疊):

> SELECT DISTINCT(s1.hour) AS ih, s2.date, s2.hour, s2.quantity, s2.amount 
    FROM sales s1 
    JOIN sales s2 ON s2.date = s1.date AND s2.hour <= s1.hour 
    WHERE s1.date = '2014-09-18' 
    ORDER by ih; 

+----+------------+------+----------+--------+ 
| ih | date  | hour | quantity | amount | 
+----+------------+------+----------+--------+ 
| 3 | 2014-09-18 | 3 |  1 | 100 | 
| 3 | 2014-09-18 | 3 |  1 |  11 | 
| 5 | 2014-09-18 | 3 |  1 | 100 | 
| 5 | 2014-09-18 | 5 |  2 | 200 | 
| 5 | 2014-09-18 | 3 |  1 |  11 | 
| 7 | 2014-09-18 | 3 |  1 | 100 | 
| 7 | 2014-09-18 | 5 |  2 | 200 | 
| 7 | 2014-09-18 | 7 |  3 | 300 | 
| 7 | 2014-09-18 | 3 |  1 |  11 | 
+----+------------+------+----------+--------+ 

求和沒有幫助,並將其添加到一塌糊塗。 第一行(小時= 3)應該有SUM(s2.quantity)等於3,但它有9. SUM(s1.quantity)對我來說顯示的是一個完整的謎。

> SELECT DISTINCT(s1.hour) AS hour, sum(s1.quantity), s2.date, SUM(s2.quantity) 
    FROM sales s1 JOIN sales s2 ON s2.date = s1.date AND s2.hour <= s1.hour 
    WHERE s1.date = '2014-09-18' 
    GROUP BY hour; 

+------+------------------+------------+------------------+ 
| hour | sum(s1.quantity) | date  | sum(s2.quantity) | 
+------+------------------+------------+------------------+ 
| 3 |    9 | 2014-09-18 |    9 | 
| 5 |    8 | 2014-09-18 |    5 | 
| 7 |    15 | 2014-09-18 |    8 | 
+------+------------------+------------+------------------+ 

獎勵積分/老闆水平: 我還需要一列,將顯示total_reference,相同的軋製總爲一個不同的日期(例如2014年9月11日)相同的週期。

+0

有一個很好的解決方案,簡單的子選擇[這裏](http://hashcode.ru/answer_link/361778/),[sqlfiddle](http://sqlfiddle.com/#!2/e46008/1) 。 – 2014-09-19 12:11:52

回答

1

如果你想在MySQL中的累計總和,最有效的方法是使用變量:

SELECT date, hour, 
     (@q := q + @q) as cumeq, (@a := a + @a) as cumea 
FROM (SELECT date, hour, SUM(quantity) as q, SUM(amount) as a 
     FROM sales s 
     WHERE s.date = '2014-09-18' 
     GROUP by date, hour 
    ) dh cross join 
    (select @q := 0, @a := 0) vars 
ORDER BY date, hour; 

如果您打算與數據庫,如Oracle,SQL Server和Postgres的工作,那麼你應該使用功能更類似的數據庫,並支持ANSI標準窗口函數。正確的方法是使用窗口函數,但MySQL不支持這些。 Postgres,SQL Server和Oracle都有可用於開發的免費版本。

此外,通過適當的索引,即使在大型表上,您也不應該遇到子查詢方法的問題。