2013-04-26 53 views
4

我有一個products表和sales表,該表記錄了每個日期期間給定產品銷售的產品數量。當然,並非所有產品每天都有銷售。如何GROUP BY連續數據(在這種情況下的日期)

我需要生成一份報告,告訴我有多少個個連續的個工作日銷售額(從最新日期到過去)以及它在這些日期內銷售的物品數量。

我想告訴你到目前爲止我已經嘗試了多少事情,但唯一成功(且緩慢的遞歸)是我的應用程序內部的解決方案,而不是SQL內部的解決方案,這正是我想要的。

我也瀏覽過幾個類似的問題,但我還沒有找到一個能夠讓我清楚自己真正需要什麼的問題。

我已經設置了一個SQLFiddle here向你展示我在說什麼。在那裏你會看到我能想到的唯一的問題,這並沒有給我我需要的結果。我還在那裏添加了註釋,顯示查詢的結果應該是什麼。

我希望這裏有人知道如何做到這一點。預先感謝您的任何意見!

舊金山

+0

我認爲你需要遞歸連接來實現MySQL不可能實現的功能。你可以在數據庫上創建存儲過程嗎? – Benos 2013-04-26 06:36:39

+0

是的,服務器是我的。 – 2013-04-26 06:40:15

回答

3

http://sqlfiddle.com/#!2/20108/1

這裏是一個存儲過程來完成這項工作

CREATE PROCEDURE myProc() 
BEGIN 
    -- Drop and create the temp table 
    DROP TABLE IF EXISTS reached; 
    CREATE TABLE reached (
    sku CHAR(32) PRIMARY KEY, 
    record_date date, 
    nb int, 
    total int) 
    ENGINE=HEAP; 

-- Initial insert, the starting point is the MAX sales record_date of each product 
INSERT INTO reached 
SELECT products.sku, max(sales.record_date), 0, 0 
FROM products 
join sales on sales.sku = products.sku 
group by products.sku; 

-- loop until there is no more updated rows 
iterloop: LOOP 
    -- Update the temptable with the values of the date - 1 row if found 
    update reached 
    join sales on sales.sku=reached.sku and sales.record_date=reached.record_date 
    set reached.record_date = reached.record_date - INTERVAL 1 day, 
     reached.nb=reached.nb+1, 
     reached.total=reached.total + sales.items; 

    -- If no more rows are updated it means we hit the most longest days_sold 
    IF ROW_COUNT() = 0 THEN 
     LEAVE iterloop; 
    END IF; 
END LOOP iterloop; 

-- select the results of the temp table 
SELECT products.sku, products.title, products.price, reached.total as sales, reached.nb as days_sold 
from reached 
join products on products.sku=reached.sku; 

END// 

然後你只需要做

call myProc() 
+0

哇,謝謝。我從來沒有想到它會花費太多,但它肯定比在應用程序級別處理速度更快,更好。非常感謝您花時間寫下這個答案。 :-) – 2013-04-26 07:39:29

+0

也許有一種更快更清潔的方式,但兩週前我遇到了幾乎相同的問題,併爲它寫了一個程序。這很容易適應你的問題 – Benos 2013-04-26 07:41:45

-1
select 
    p.*, 
    sum(s.items) sales, 
    count(s.record_date) days_sold 
from 
    products p 
join 
    sales s 
    on 
    s.sku = p.sku 
where record_date between '2013-04-18 00:00:00' and '2013-04-26 00:00:00' 
group by sku; 
+0

謝謝,但是......它不會只記錄連續的日期記錄,也不會計算在過去的記錄中,因爲它們只是連續的。 – 2013-04-26 07:34:32

2

在P A解決方案沒有存儲過程茜SQL:Fiddle

SELECT sku 
    , COUNT(1) AS consecutive_days 
    , SUM(items) AS items 
FROM 
(
    SELECT sku 
     , items 
     -- generate a new guid for each group of consecutive date 
     -- ie : starting with day_before is null 
     , @guid := IF(@sku = sku and day_before IS NULL, UUID(), @guid) AS uuid 
     , @sku := sku AS dummy_sku 
    FROM 
    (
    SELECT currents.sku 
     , befores.record_date as day_before 
     , currents.items 
    FROM sales currents 
     LEFT JOIN sales befores 
     ON currents.sku = befores.sku 
     AND currents.record_date = befores.record_date + INTERVAL 1 DAY 
    ORDER BY currents.sku, currents.record_date 
) AS main_join 
    CROSS JOIN (SELECT @sku:=0) foo_sku 
    CROSS JOIN (SELECT @guid:=UUID()) foo_guid 
) AS result_to_group 
GROUP BY uuid, sku 

查詢是真的沒有那麼難。通過cross join (SELECT @type:=0) type聲明變量。然後在選擇中,您可以逐行設置變量值。模擬秩函數是必要的。

+0

哇。我將不得不進行一些研究以瞭解您的查詢。這將是我第一次使用'items,@guid:= IF(...'和'cross join'等東西。謝謝,這似乎是一個非常大的問題。:-) – 2013-04-26 08:37:33

+0

@FranciscoZarabozo:是不是硬。測試每個子查詢並觀察結果,然後您可以輕鬆理解發生了什麼。 – 2013-04-26 08:40:11

+0

我真的很喜歡這種方式,如果銷售表隨着時間增長很多,那麼性能與商店過程有什麼關係?你的陳述是獲得連續日期的所有塊,這是很棒的,但可能是一張大桌子上的問題。無論如何非常感謝您的查詢,我學到了很多分析 – Benos 2013-04-26 09:01:51