将MySQL结果分组为7天增量

时间:2014-08-18 02:01:36

标签: mysql

希望有人能够帮助我。

假设我有下面列出的表格。主机可以在同一天出现多次,通常使用不同的备份。

+------------------+--------------+
| Field            | Type         | 
+------------------+--------------+
| startdate        | date         |
| host             | varchar(255) | 
| backupsize       | float(6,2)   |  
+------------------+--------------+

我怎样才能找到7天增量从最早的日期开始到最后一个日期的备份总和?我不介意过去几天是否被切断,因为它们没有达到7天的增量。

期望的输出(首选):

+------------+----------+----------+----------+-----
|Week of     | system01 | system02 | system03 | ...
+------------+----------+----------+----------+-----
| 2014/07/30 | 2343.23  | 232.34   | 989.34   |
+------------+----------+----------+----------+-----
| 2014/08/06 | 2334.7   | 874.13   | 234.90   |
+------------+----------+----------+----------+-----
| ...        | ...      | ...      | ...      |

OR

+------------+------------+------------+------
|Host        | 2014/07/30 | 2014/08/06 | ...
+------------+------------+------------+------
| system01   | 2343.23    | 2334.7     | ...  
+------------+------------+------------+-------
| system02   | 232.34     | 874.13     | ...
+------------+------------+------------+-------
| system03   | 989.34     | 234.90     | ...
+------------+------------+------------+-------
| ...        | ...        | ...        |       

日期格式不是问题,只要它以某种方式被识别。此外,主机的顺序也不是问题。谢谢!

3 个答案:

答案 0 :(得分:3)

最简单的方法是获取最早的日期并计算天数:

select x.minsd + interval floor(datediff(x.minsd, lb.startdate) / 7) day as `Week of`,
       host,
       sum(backupsize)
from listedbelow lb cross join
     (select min(startdate) as minsd from listedbelow lb) x
group by floor(datediff(x.minsd, lb.startdate) / 7)
order by 1;

这会在每行上生成一个week ofhost的表单。您可以根据需要调整结果。

答案 1 :(得分:0)

我假设您想要的是bakcupsizehost分组的总和以及您正在谈论的七天间隔。

我的解决方案是这样的:

  1. 您需要定义第一个日期,然后"创建"包含所需日期的列(七天结束时间)
  2. 然后我会把它分组。
  3. 我认为临时表和带有临时变量的小技巧是解决这个问题的最佳方法,所以:

    drop table if exists temp_data;
    create temporary table temp_data
    select a.*
         -- The @d variable will have the date that you'll use later to group the data.
         , @d := case
              -- If the current "host" value is the same as the previous one, then...
               when @host_prev = host then 
                   -- ... if @d is not null and is within the seven-day period,
                   -- then leave the value of @d intact; in other case, add 7 days to it.
                   case
                       when @d is not null or a.startdate <= @d then @d
                       -- The coalesce() function will return the first not null argument
                       -- (just as a precaution)
                       else dateadd(coalesce(@d, a.startdate), interval +7 day)
                   end
               -- If the current "host" value is not  the same as the previous one, 
               -- then take the current date (the first date of the "new" host) and add
               -- seven days to it.
               else @d = dateadd(a.startdate, interval +7 day) 
           end as date_group
         -- This is needed to perform the comparisson in the "case" piece above
         , @host_prev := a.host as host2
    from
           (select @host_prev = '', @d = null) as init -- Initialize the variables
         , yourtable as a
    -- IMPORTANT: This will only work if you order the data properly
    order by a.host, a.startdate;
    -- Add indexes to the temp table, to make things faster
    alter table temp_data
       add index h(host),
       add index dg(date_group)
       -- OPTIONAL: You can drop the "host2" column (it is no longer needed)
       -- , drop column host2
       ;
    

    现在,您可以获取分组数据:

    select a.host, a.date_group, sum(a.bakcupsize) as backupsize
    from temp_data as a
    group by a.host, a.date_group;
    

    这将为您提供不透明的数据。如果您想使用它构建数据透视表,我建议您查看this article和/或read this question and its answers。简而言之,你必须建立一个动态的&#34; sql指令,用它准备一个语句并执行它。


    当然,如果你想按周分组,那么这是一个更简单的方法:

    drop table if exists temp_data2;
    create temporary table temp_data2
    select a.*
         -- The following will give you the end-of-week date
         , dateadd(a.startdate, interval +(6 - weekday(a.startdate)) day) as group_date
    from yourtable as a;
    alter table temp_data
       add index h(host),
       add index dg(date_group);
    select a.host, a.date_group, sum(a.bakcupsize) as backupsize
    from temp_data as a
    group by a.host, a.date_group;
    

    我将枢轴部分留给你。

答案 2 :(得分:0)

因此,我能够使用我推荐的解决方案中的概念以及我在本网站上找到的其他一些解决方案,使用我创建的程序来确定符合我需求的解决方案。过程SUM以7天为增量以及进行转动。

DELIMITER $$
CREATE PROCEDURE `weekly_capacity_by_host`()
BEGIN
SELECT MIN(startdate) into @start_date FROM testtable;

SET @SQL = NULL;
SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
      'SUM(if(host=''',host,''', backupsize, 0)) as ''',host,''''
    )
  ) INTO @SQL
FROM testtable;

SET @SQL = CONCAT('SELECT 1 + DATEDIFF(startdate, ''',@start_date,''') DIV 7 AS week_num
  , ''',@start_date,''' + INTERVAL (DATEDIFF(startdate, ''',@start_date,''') DIV 7) WEEK AS week_start,
  ', @SQL,' 
  FROM testtable group by week_num'
);

PREPARE stmt FROM @SQL;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END$$
DELIMITER ;

输出如下:

mysql> call weekly_capacity_by_host;
+----------+------------+----------+----------+----------+----------+
| week_num | week_start | server01 | server02 | server03 | server04 |
+----------+------------+----------+----------+----------+----------+
|        1 | 2014-06-11 |  1231.08 |    37.30 |    12.04 |    68.17 |
|        2 | 2014-06-18 |  1230.98 |    37.30 |    11.76 |    68.13 |
|        3 | 2014-06-25 |  1243.12 |    37.30 |     8.85 |    68.59 |
|        4 | 2014-07-02 |  1234.73 |    37.30 |    11.77 |    67.80 |
|        5 | 2014-07-09 |   341.32 |     0.04 |     0.14 |     4.94 |
+----------+------------+----------+----------+----------+----------+
5 rows in set (0.03 sec)