【问题标题】:MySQL query to count items by week for the current 52-weeks?MySQL 查询按周计算当前 52 周的项目?
【发布时间】:2012-04-08 13:20:33
【问题描述】:

我有一个要更改的查询,以便它为我提供当前 52 周的计数。此查询使用我制作的日历表,其中包含固定范围内的日期列表。目前的查询是选择最大和最小日期,而不一定是过去 52 周。

我想知道如何使我的日历表保持最新状态,以便我可以获得过去 52 周(即从现在到一年前)的信息。还是有另一种方法可以使查询独立于使用日历表?

这是查询:

SELECT calendar.datefield AS date, IFNULL(SUM(purchaseyesno),0) AS item_sales
FROM items_purchased join items on items_purchased.item_id=items.item_id 
RIGHT JOIN calendar ON (DATE(items_purchased.purchase_date) = calendar.datefield)
WHERE (calendar.datefield BETWEEN (SELECT MIN(DATE(purchase_date)) 
FROM items_purchased) AND (SELECT MAX(DATE(purchase_date)) FROM items_purchased)) 
GROUP BY week(date)

想法?

【问题讨论】:

  • 为什么你有一个日历表而不只是在该表中使用 DATE 或 DATETIME 列?
  • @Ryan Kempt,这可能确实是 OP 所要求的。此外,当您需要一系列日期时,日期函数也没有那么有用。
  • 当您必须为每个时期都有一个 bin 并且可能没有任何特定 bin 的数据时,使用日历表。
  • 嗨 Ryan,日历表是在没有购买的给定日期生成 0 的商品销售额,否则查询结果仅限于有商品销售的日期。我的最终用途是绘制结果图,因此具有所有个日期而不只是具有非零值的日期很重要,感谢 Jim 和 Jason 帮助 Clarify!

标签: mysql sql date calendar


【解决方案1】:

有些人不喜欢这种方法,但我倾向于使用包含 0 - 1000 值的虚拟表,然后使用派生表来生成所需的范围 -

CREATE TABLE dummy (`num` INT NOT NULL);
INSERT INTO dummy VALUES (0), (1), (2), (3), (4), (5), .... (999), (1000);

如果您有一个具有自动递增 id 和大量行的表,您可以从中生成它 -

CREATE TABLE `dummy`
SELECT id AS `num` FROM `some_table` WHERE `id` <= 1000;

记得插入 0 值。

SELECT CURRENT_DATE - INTERVAL num DAY
FROM dummy
WHERE num < 365

因此,将这种方法应用于您的查询,您可以执行以下操作 -

SELECT WEEK(calendar.datefield) AS `week`, IFNULL(SUM(purchaseyesno),0) AS item_sales
FROM items_purchased join items on items_purchased.item_id=items.item_id 
RIGHT JOIN (
    SELECT (CURRENT_DATE - INTERVAL num DAY) AS datefield
    FROM dummy
    WHERE num < 365
) AS calendar ON (DATE(items_purchased.purchase_date) = calendar.datefield)
WHERE calendar.datefield >= (CURRENT_DATE - INTERVAL 1 YEAR)
GROUP BY week(datefield) -- shouldn't this be datefield instead of date?

【讨论】:

  • 嗨 nnichols,非常感谢,我会试一试,为什么人们不喜欢这种方法?因为代码看起来很难看?还是查询很慢?还是...?
  • 我不知道为什么。这根本不应该有任何性能问题,我个人认为这是一个相当优雅的解决方案。
  • 好的,我制作了虚拟桌子。感谢那里的建议。但是,我认为我对您的陈述感到特别困惑:WHERE calendar.datefield &gt;= (CURRENT_DATE - INTERVAL 1 YEAR)。就目前而言,我的日历表从 2008 年 1 月到 2010 年 9 月。相等性是否意味着我必须不断更新我的日历表才能保持在去年?顺便说一句,如果我 group by week(datefield) 而不是 group by week(date),您的查询会产生 52 周的商品销售。 date 未定义。但是,我仍然不确定这 52 周的商品销售是否是最近的 52 周。想法?
  • 抱歉被 5 分钟的编辑时间限制打断了...我不确定这 52 周的商品销售是否是最近的 52 周,因为我看不到实际情况日期。 week 字段只是数字 1 到 52。有什么想法吗?
  • WHERE 子句只是一个示例,说明如何过滤超过一年前的所有内容。如果您运行查询SELECT CURRENT_DATE - INTERVAL num DAY FROM dummy WHERE num &lt; 365,您应该会看到代表去年所有日期的日期列表。然后将其加入您的 items_purchased 表。因此,它应该按周为您提供过去一年的销售额。将 MAX(calendar.datefield) 添加到您的字段列表中,以便您可以查看每周的最后一天,如果您愿意,也可以添加 MIN()。
【解决方案2】:

我通常使用@sql 变量即时“模拟”一个表,然后加入系统中至少有你想要的周数的任何表。注意...在处理日期时,我通常喜欢仅使用日期部分,这意味着上午 12:00:00。此外,通过将“EndOfWeek”的开始日期提前 7 天,您现在可以为给定时间段内的记录应用 BETWEEN 子句……例如您的每周需求。

我已经应用了这样一个示例来协调基于日期关联到每周的加入......因为你的

select 
      DynamicCalendar.StartOfWeek,
      COALESCE( SUM( IP.PurchaseYesNo ), 0 ) as Item_Sales
   from 
      ( select
              @weekNum := @weekNum +1 as WeekNum,
              @startDate as StartOfWeek,
              @startDate := date_add( @startDate, interval 1 week ) EndOfWeek
           from 
              ( select @weekNum := 0,
                       @startDate := date(date_sub(now(), interval 1 year ))) sqlv,
              AnyTableThatHasAtLeast52Records,
           limit
             52 ) DynamicCalendar
      LEFT JOIN items_purchased IP
         on IP.Purchase_Date bewteen DynamicCalendar.StartOfWeek 
                            AND DynamicCalendar.EndOfWeek
   group by
      DynamicCalendar.StartOfWeek

这是在您的“PurchaseYesNo”值直接在您购买的表中的前提下。如果是这样,则无需加入 ITEMS 表。如果该字段位于 items 表中,那么我将为您的 items 表添加一个 LEFT JOIN 并从中获得价值。

但是,您可以在许多情况下使用 dynamicCalendar 上下文。

【讨论】:

    猜你喜欢
    • 2018-08-15
    • 1970-01-01
    • 2021-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多