MySQL组由开始和结束时间组成

时间:2016-06-30 20:26:44

标签: mysql group-by

我在MySQL中有一个名为map_item_group的表,如下例所示:

item_serial | group_code | start_date | end_date
===================================================
item1       | group1     | 2015-01-01 | 2016-01-01
item1       | group2     | 2016-02-01 | 2016-03-15
item2       | group1     | 2015-06-01 | 2016-06-30
item1       | group2     | 2016-05-18 | 2016-06-30

我想创建一个名为group_info的MySQL视图,如下所示:

group_code | start_date | end_date   | items_string   
=======================================================
group1     | 2015-01-01 | 2015-06-01 | item1    
group1     | 2015-06-01 | 2016-01-01 | item1,item2
group1     | 2016-01-01 | 2016-06-30 | item2   
group2     | 2016-02-01 | 2016-03-15 | item1
group2     | 2016-05-18 | 2016-06-30 | item1        

换句话说,我想为每个组显示一行,在每个时间跨度显示该组中的项目。

只需按group_code,start_date和end_date(即SELECT group_code, start_date, end_date, GROUP_CONCAT(item_serial) FROM map_item_group GROUP BY group_code, start_date, end_date)进行分组,就无法提供所需的输出。

我可以想象用子查询做到这一点的方法,但MySQL视图中不允许使用子查询。我可以创建其他视图来代替子查询作为一种解决方法,但我宁愿避免在我的模式中添加一堆额外的视图。最干净的方法是什么?

1 个答案:

答案 0 :(得分:0)

  • 首先,我使用(start + end) group_code创建所有日期UNION的列表我调用T1,但应选择其他名称
  • 然后使用变量将row_number设置为每个日期。子查询T1T2
  • 然后必须复制代码以将结果连接到自身并创建范围。子查询R
    • 您可以简化它,使其成为一个独立的视图。
  • 现在我有了范围,加入到原始表格以查看该项目是否属于该范围。

<强> OUPUT

enter image description here

<强> SQL Demo

SELECT R.`group_code`, R.`start_date`, R.`end_date`, GROUP_CONCAT(T.item_serial SEPARATOR ', ') items
FROM (
        SELECT T1.`group_code`, T1.range_date as start_date, T2.range_date as end_date
        FROM (    
                SELECT `group_code`, range_date, 
                        @rn := IF( @grpCode = `group_code`, @rn + 1 , IF(@grpCode := `group_code`, 1, 1)) as rn

                FROM (
                        SELECT `group_code`, `start_date` as range_date
                        FROM Table1
                        UNION
                        SELECT `group_code`, `end_date` as range_date
                        FROM Table1
                        ORDER BY 1, 2
                     ) as T1, 
                     (SELECT @rn := 0, @grpCode := '') r
            ) T1 
        JOIN (
                SELECT `group_code`, range_date, 
                        @rn := IF( @grpCode = `group_code`, @rn + 1 , IF(@grpCode := `group_code`, 1, 1)) as rn

                FROM (
                        SELECT `group_code`, `start_date` as range_date
                        FROM Table1
                        UNION
                        SELECT `group_code`, `end_date` as range_date
                        FROM Table1
                        ORDER BY 1, 2
                     ) as T1, 
                     (SELECT @rn := 0, @grpCode := '') r    
            ) T2
          ON T1.rn = T2.rn -1
         AND T1.group_code = T2.group_code
    ) R
JOIN Table1 T
  ON R.start_date < T.end_date
 AND R.end_date   > T.start_date
 AND R.group_code = T.group_code
GROUP BY R.`group_code`, R.`start_date`, R.`end_date`
ORDER BY 1,2, 4