MySQL按周分组

时间:2012-03-21 16:42:48

标签: mysql group-by

我有大量的记录,其交易日期时间字段可以追溯到几年前。我想在今年和去年的同一时间跨度之间进行比较分析。我如何按周分组超过3个月?

我使用YEARWEEK和WEEK功能遇到了问题,因为2012年开始的那一天与2011年开始的那天。

鉴于我每天从1月1日到当天都有日期时间的记录,并且记录的日期时间与上一年相同,我如何按周分组,以便输出与日期之和如下:01/01/2011 ,01/08/2011,01/15/2011等,以及01/01 / 2012,01 / 08 / 2012,01 / 15/2012等?

我的查询到目前为止如下:

SELECT 
    DATE_FORMAT(A.transaction_date, '%Y-%m-%d') as date,
    ROUND(sum(A.quantity), 3) AS quantity,
    ROUND(sum(A.total_amount), 3) AS amount,
    A.product_code, 
    D.fuel_type_code, 
    D.fuel_type_name, 
    C.customer_code, 
    C.customer_name 
FROM 
    cl_transactions AS A
INNER JOIN 
    card AS B ON A.card_number=B.card_number 
INNER JOIN 
    customer AS C ON B.customer_code=C.customer_code 
INNER JOIN 
    fuel_type AS D ON A.fuel_type=D.fuel_type_code 
WHERE 
    ((A.transaction_date >= DATE_FORMAT(NOW() - INTERVAL 3 MONTH, '%Y-%m-01')) OR (A.transaction_date - INTERVAL 1 YEAR >=  DATE_FORMAT(NOW() - INTERVAL 15 MONTH, '%Y-%m-01') AND A.transaction_date <= NOW() - INTERVAL 1 YEAR))
GROUP BY 
    A.transaction_date, fuel_type_code;

我基本上喜欢能够实现以下伪查询的东西:

GROUP BY 
    STARTING FROM THE OLDEST DATE (A.transaction_date + INTERVAL 6 DAY)

1 个答案:

答案 0 :(得分:1)

我开始使用sqlvariables进行内部查询,以构建今年和每年各年/月/日开始的年份和去年的范围(例如分别为2012-01-01和2011-01-01) 。从那时起,我还预先格式化了最终输出的日期,因此你有一个主日期基础显示反映“今年”周的任何一天。

由此,我加入交易表,其中交易日期是当前周的相应开始和下周开始的BETWEEN。由于日期/时间戳包括小时分钟,因此2012-01-01本身暗示为当天的12:00:00(午夜)。并且将在7天后的12:00:00之间进行。该日期将成为下周的开始日期。

因此,通过加入EITHER last yr或此yr时间段之间的日期,它具有相同的组资格。因此,字段选择按去年或今年分别进行ROUND(SUM(IF()))。如果收到的交易日期少于当前年度的开始日期,那么它必须是上一年的记录,否则是当前年度的记录。因此,分别添加值本身,或者应用为零。

现在,你有了这个小组。它符合条件的那一周已经通过“ThisYearWeekOf”格式化列从内部查询准备,无论计算的其他方式是“YEARWEEK()”还是“WEEK()”。日期范围负责我们的资格。

最后,我添加了燃料类型作为连接,并将其作为分组包括在内。您必须按所有非聚合列分组才能获得正确的SQL,尽管MySQL可以通过抓取给定组的第一个条目(如果它未在group by中指定)来实现。

要关闭,我DID包含客户的信息,因为您在组中没有它并且似乎不适用...它只会随意抓取一个。但是,我已将它添加到组中,所以现在您的记录将显示在每个客户级别,每种产品和燃料类型,今年和去年之间的销售量和数量。

SELECT
      JustWeekRange.ThisYearWeekOf,
      CTrans.product_code,
      FT.fuel_type_code, 
      FT.fuel_type_name, 
      C.customer_code, 
      C.customer_name,
      ROUND( SUM( IF( CTrans.transaction_date < JustWeekRange.ThisYrWeekStart, CTrans.Quantity, 0 )), 3) as LastYrQty,
      ROUND( SUM( IF( CTrans.transaction_date < JustWeekRange.ThisYrWeekStart, CTrans.total_amount, 0 )), 3) as LastYrAmt,
      ROUND( SUM( IF( CTrans.transaction_date < JustWeekRange.ThisYrWeekStart, 0, CTrans.Quantity )), 3) as ThisYrQty,
      ROUND( SUM( IF( CTrans.transaction_date < JustWeekRange.ThisYrWeekStart, 0, CTrans.total_amount )), 3) as ThisYrAmt,
   FROM 
      ( SELECT 
                 DATE_FORMAT(@ThisYearDate, '%Y-%m-%d') as ThisYearWeekOf,
                 @LastYearDate as LastYrWeekStart,
                 @ThisYearDate as ThisYrWeekStart,
                 @LastYearDate := date_add( @LastYearDate, interval 7 day ) LastYrStartOfNextWeek,
                 @ThisYearDate := date_add( @ThisYearDate, interval 7 day ) ThisYrStartOfNextWeek
            FROM 
                 (select @ThisYearDate := '2012-01-01',
                         @LastYearDate := '2011-01-01' ) sqlvars,
                 cl_transactions justForLimit
            HAVING
               ThisYrWeekStart < '2012-04-01'
            LIMIT 15 ) JustWeekRange

      JOIN cl_transactions AS CTrans
         ON    CTrans.transaction_date BETWEEN 
               JustWeekRange.LastYrWeekStart AND JustWeekRange.LastYrStartOfNextWeek
           OR  CTrans.transaction_date BETWEEN 
               JustWeekRange.ThisYrWeekStart AND JustWeekRange.ThisYrStartOfNextWeek

      JOIN fuel_type FT
         ON CTrans.fuel_type = FT.fuel_type_code

      JOIN card 
         ON CTrans.card_number = card.card_number 
         JOIN customer AS C 
            ON card.customer_code = C.customer_code 

   GROUP BY
      JustWeekRange.ThisYearWeekOf,
      CTrans.product_code,
      FT.fuel_type_code, 
      FT.fuel_type_name,
      C.customer_code, 
      C.customer_name