如何使用MySQL对连续范围进行分组

时间:2012-09-05 06:59:53

标签: mysql gaps-and-islands date-range

我有一张包含类别,日期和费率的表格。每个类别对于不同的日期可以有不同的费率,一个类别在给定日期只能有一个费率。

Id        CatId    Date        Rate 
------  ------   ------------   ---------
000001      12   2009-07-07     1
000002      12   2009-07-08     1
000003      12   2009-07-09     1
000004      12   2009-07-10     2
000005      12   2009-07-15     1
000006      12   2009-07-16     1
000007      13   2009-07-08     1
000008      13   2009-07-09     1
000009      14   2009-07-07     2
000010      14   2009-07-08     1
000010      14   2009-07-10     1

独特指数(catid,Date,Rate) 我希望每个类别对所有连续日期范围进行分组,并仅保留范围的开头和结尾。 对于前面的示例,我们将:

CatId    Begin          End            Rate 
------   ------------   ------------   ---------
12        2009-07-07    2009-07-09     1
12        2009-07-10    2009-07-10     2
12        2009-07-15    2009-07-16     1  
13        2009-07-08    2009-07-09     1  
14        2009-07-07    2009-07-07     2
14        2009-07-08    2009-07-08     1
14        2009-07-10    2009-07-10     1

我在the forum中找到了一个类似的解决方案,它没有完全给出结果

WITH    q AS
        (
        SELECT  *,
                ROW_NUMBER() OVER (PARTITION BY CatId, Rate ORDER BY [Date]) AS rnd,
                ROW_NUMBER() OVER (PARTITION BY CatId ORDER BY [Date]) AS rn
        FROM    my_table
        )
SELECT  CatId AS catidd, MIN([Date]) as beginn, MAX([Date])as endd, Rate
FROM    q
GROUP BY  CatId, rnd - rn, Rate

SEE SQL FIDDLE 我怎么能在mysql中做同样的事情? 请帮忙!

3 个答案:

答案 0 :(得分:6)

MySQL不支持分析函数,但您可以使用user-defined variables

模拟此类行为
SELECT   CatID, Begin, MAX(Date) AS End, Rate
FROM (
  SELECT   my_table.*,
           @f:=CONVERT(
             IF(@c<=>CatId AND @r<=>Rate AND DATEDIFF(Date, @d)=1, @f, Date), DATE
           ) AS Begin,
           @c:=CatId, @d:=Date, @r:=Rate
  FROM     my_table JOIN (SELECT @c:=NULL) AS init
  ORDER BY CatId, Rate, Date
) AS t
GROUP BY CatID, Begin, Rate

sqlfiddle上查看。

答案 1 :(得分:3)

SELECT catid,min(ddate),max(ddate),rate
FROM (
    SELECT
        Catid,
        Ddate,  
        rate,
        @rn := CASE WHEN (@prev <> rate 
           or DATEDIFF(ddate, @prev_date)>1) THEN @rn+1 ELSE @rn END AS rn,
        @prev := rate,
        @prev_id := catid ,
        @prev_date :=ddate
    FROM (
        SELECT CatID,Ddate,rate 
        FROM rankdate
        ORDER BY CatID, Ddate ) AS a , 
        (SELECT @prev := -1, @rn := 0, @prev_id:=0 ,@prev_date:=-1) AS vars      

) T1 group by catid,rn

注意:Mysql Workspace中不需要行(SELECT @prev:= -1,@ rn:= 0,@ prev_id:= 0,@ prev_date:= - 1)AS vars ,但它在PHP mysql_query函数中。

SQL FIDDLE HERE

答案 2 :(得分:0)

我知道我迟到了,仍然发布一个对我有用的解决方案。 有同样的问题,这就是我得到它的方式

使用变量

找到了一个很好的解决方案
SELECT  MIN(id) AS id, MIN(date) AS date, MIN(state) AS state, COUNT(*) cnt
FROM    (
    SELECT  @r := @r + (@state != state OR @state IS NULL) AS gn,
            @state := state AS sn,
            s.id, s.date, s.state
    FROM    (
            SELECT  @r := 0,
                    @state := NULL
            ) vars,
            t_range s
    ORDER BY
            date, state
    ) q
GROUP BY gn

更多详情请见:https://explainextended.com/2009/07/24/mysql-grouping-continuous-ranges/