2014-12-11 113 views
0

我正在構建查詢以返回每日銷售數據。我目前的查詢將返回類似於下面的表格:MySQL報告 - 填寫空日期

---------------------------------- 
| DATE  | SKU  | TOTAL | 
---------------------------------- 
| 2014-11-01 | AV155_A | 209.00 | 
| 2014-11-02 | AV155_B | 627.00 | 
| 2014-11-04 | AV155_C | 279.00 | 
| 2014-11-05 | AV155 | 279.00 | 
| 2014-11-08 | AV1556_A | 209.00 | 
| 2014-11-09 | AV1556_B | 627.00 | 
| 2014-11-10 | AV1556_C | 279.00 | 
| 2014-11-12 | AV1556 | 279.00 | 

我想是一個成績表顯示每一天,即使有該日期沒有數據點。事情是這樣的:

---------------------------------- 
| DATE  | SKU  | TOTAL | 
---------------------------------- 
| 2014-11-01 | AV155_A | 209.00 | 
| 2014-11-02 | AV155_B | 627.00 | 
| 2014-11-03 |   |  0 | 
| 2014-11-04 | AV155_C | 279.00 | 
| 2014-11-05 | AV155 | 279.00 | 
| 2014-11-06 |   |  0 | 
| 2014-11-07 |   |  0 | 
| 2014-11-08 | AV1556_A | 209.00 | 
| 2014-11-09 | AV1556_B | 627.00 | 
| 2014-11-10 | AV1556_C | 279.00 | 
| 2014-11-11 |   |  0 | 
| 2014-11-12 | AV1556 | 279.00 | 

查詢我目前有看起來像這樣:

select 
    DATE_FORMAT(created_on, '%m-%d-%Y') as date, 
    sku, 
    SUM(price) as total 
FROM order_items 
WHERE created_on between FROM_UNIXTIME(1415577600) AND NOW() 
GROUP BY MONTH(created_on), DAY(v.created_on), order_item_sku; 
+0

我相信要做到這一點,你需要執行一個UPDATE插入所需範圍內沒有數據的日期行,或者使用SQL的流控制和編程,即創建一個循環訪問日期範圍的存儲過程。沒有看到如何在簡單的SELECT查詢中做到這一點... – RobP 2014-12-11 01:15:46

回答

2

您需要使用外連接。最簡單的方法是,如果你有一個日曆表,但你可以做一個在飛行:

select c.thedate, oi.sku, sum(price) as total 
from (select date('2014-11-01') as thedate union all 
      date('2014-11-02') as thedate union all 
      date('2014-11-03') as thedate union all 
      date('2014-11-04') as thedate union all 
      date('2014-11-05') as thedate union all 
      date('2014-11-06') as thedate union all 
      date('2014-11-07') as thedate union all 
      date('2014-11-08') as thedate union all 
      date('2014-11-09') as thedate union all 
      date('2014-11-10') as thedate union all 
      date('2014-11-11') as thedate union all 
      date('2014-11-12') as thedate 
    ) c left join 
     order_items oi 
     on c.thedate = date(oi.created_on) 
where oi.created_on between FROM_UNIXTIME(1415577600) AND NOW() 
group by ci.thedate, oi.sku 
+0

嗯。是的,我將在我的API中使用這個查詢,所以我需要能夠動態生成查詢。我將如何去使用日曆表?我還看到了有關使用其他表的ID來動態生成一系列日期的信息。 – 2014-12-11 01:20:35

+0

@JoelBrewer。 。 。如果您是通過API來完成這項工作的,那麼您不能只在應用程序層中添加額外的行嗎? – 2014-12-11 02:03:18

1

下面是解決了日期的靈活列表需要一個答案。您需要找出一種方法來獲取包含適當範圍內所有日期的虛擬表格,然後將它們加入摘要。這是一個查詢,將獲得該範圍內的日期。

SELECT mintime + INTERVAL seq.seq DAY AS reportdate 
    FROM (
     SELECT MIN(DATE(created_on)) AS mintime, 
       MAX(DATE(created_on)) AS maxtime 
      FROM order_items 
     WHERE created_on >= starting_time 
      AND created_on <= NOW() 
     ) AS order_items 
    JOIN seq_0_to_999 AS seq 
        ON seq.seq < TIMESTAMPDIFF(DAY,mintime,maxtime) 

這是怎麼回事?三件事。

  1. 我們有一個子查詢,它決定我們關心報告的第一天和最後一天(最小和最大created_on)。

  2. 我們將時間範圍應用於該查詢。我喜歡避免使用BETWEEN作爲時間戳範圍,因爲它經常在錯誤的一秒錯誤中得到錯誤的結束時間。

  3. 我們有一個名爲seq_0_to_999的表。它包含一千個基數的序列:從零開始的整數。更多關於這一點。

然後,您可以將其作爲子查詢加入到您的聚合查詢中,以獲取所列範圍中的所有日期,如此。

select DATE_FORMAT(d.reportdate, '%m-%d-%Y') as date, 
     sku, 
     SUM(price) as total 
    FROM (
      SELECT mintime + INTERVAL seq.seq DAY AS reportdate 
      FROM (
        SELECT MIN(DATE(created_on)) AS mintime, 
         MAX(DATE(created_on)) AS maxtime 
        FROM order_items 
        WHERE created_on >= starting_time 
        AND created_on <= NOW() 
       ) AS order_items 
      JOIN seq_0_to_999 AS seq 
           ON seq.seq < TIMESTAMPDIFF(DAY,mintime,maxtime) 
     ) AS d 
    LEFT JOIN order_items ON d.reportdate = DATE(order_items.created_on)  
    WHERE created_on >= starting_time 
    AND created_on <= NOW() 
    GROUP BY d.reportdate, sku 
    ORDER BY d.reportdate, sku 

它看起來像一個查詢大討厭的毛球。但是,如果您將其視爲由各種查詢層組成的三明治,則確實不那麼複雜。

它使用LEFT JOIN,因此它確保即使您的order_items表中沒有相應的數據,該範圍內的所有日期都會保留。

最後,這個seq_0_to_999表怎麼辦?我們從哪裏獲得從零開始的整數?答案是這樣的:我們必須安排這樣做;這些數字不是內置在MySQL中的。 (它們被構建到名爲MariaDB的MySQL分支中。)在其0-9創建一個整數短表,就像這樣:

DROP TABLE IF EXISTS seq_0_to_9; 
CREATE TABLE seq_0_to_9 AS 
    SELECT 0 AS seq UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 
    UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9; 

然後創建一個連接該表與自身,以便產生1000個組合是這樣的:

DROP VIEW IF EXISTS seq_0_to_999; 
CREATE VIEW seq_0_to_999 AS (
SELECT (a.seq + 10 * (b.seq + 10 * c.seq)) AS seq 
    FROM seq_0_to_9 a 
    JOIN seq_0_to_9 b 
    JOIN seq_0_to_9 c 
); 

我在這裏寫一些詳細的內容在http://www.plumislandmedia.net/mysql/filling-missing-data-sequences-cardinal-integers/

+0

嗯。這看起來非常好,我認爲我真的很接近,但由於某種原因,它仍然沒有填補缺失的日期.. – 2014-12-11 03:16:22