2013-04-26 54 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