2012-09-05 34 views
7

Tôi có bảng chứa danh mục, ngày và tỷ lệ. Mỗi danh mục có thể có các mức giá khác nhau cho các ngày khác nhau, một danh mục chỉ có thể có một tỷ lệ tại một ngày cụ thể.Cách nhóm các phạm vi liên tục bằng cách sử dụng MySQL

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 

index Unique (CatID, Date, Rate) Tôi muốn cho từng loại vào nhóm tất cả các ngày dao động liên tục và giữ chỉ bắt đầu và kết thúc của dãy núi này. Đối với ví dụ trước, chúng ta sẽ có:

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 

Tôi tìm thấy một giải pháp tương tự trong the forum mà không chính xác cho kết quả

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 Làm thế nào tôi có thể làm điều tương tự trong mysql ? Xin vui lòng giúp đỡ!

+0

Tại sao ví dụ hiển thị của bạn cho '(CatID, Rate) = (14,1) 'phạm vi kết quả từ' 2009-07-08' đến '2009-07-10' khi không có' 2009-07-09' trong bảng bên dưới? c.f. '(CatId, Rate) = (12,1)', tạo ra hai dãy kết quả do sự gián đoạn của nó. – eggyal

+0

Cảm ơn eggyal, bây giờ nó đã sửa chữa – Fouzi

Trả lời

6

MySQL không hỗ trợ chức năng phân tích, nhưng bạn có thể bắt chước hành vi như vậy với 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 

Xem nó trên sqlfiddle.

+0

Dường như hoạt động như mong đợi! Cảm ơn rất nhiều eggyal! – Fouzi

+1

'<=>' có nghĩa là gì? –

+1

@vanabel: Đây là [Toán tử an toàn NULL] của MySQL (http://dev.mysql.com/doc/en/comparison-operators.html#operator_equal-to). – eggyal

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 

Lưu ý: Điểm mấu (SELECT @prev: = -1, @rn: = 0, @prev_id: = 0, @ prev_date: = - 1) AS vars là không cần thiết trong Mysql Workspace, nhưng nó nằm trong hàm mysql_query của PHP.

SQL FIDDLE HERE

+0

nếu chúng ta xóa bản ghi với ID = '000004' trả về truy vấn của bạn (bắt đầu: 2009-07-07, kết thúc: 2009-07-16, tỷ lệ: 1) điều đó không chính xác vì có một khoảng cách, nó sẽ trở lại (bắt đầu: 2009-07-07, kết thúc: 2009-07-09, tỷ lệ: 1) và (bắt đầu: 2009-07-15, kết thúc: 2009-07-16, tỷ lệ: 1). [SQL FIDDLE HERE] (http://sqlfiddle.com/#!2/513b2/1) – Fouzi

+0

@BoussahelBachir, tôi đã chỉnh sửa câu trả lời. trong trường hợp này, cần phải bao gồm các điều kiện của dateiff để phục vụ cho tình hình bạn đề cập đến. – sel

+0

Bạn dường như không thử nghiệm '@ prev_id' ở bất kỳ đâu ... điều gì sẽ xảy ra nếu hai ngày tiếp giáp có cùng' Giá trị' có một 'CatId' khác? – eggyal

0

Tôi biết mình đến muộn, vẫn đăng một giải pháp phù hợp với mình. Đã cùng một vấn đề, đây là cách tôi đã nhận nó

Tìm thấy một giải pháp tốt sử dụng các biến

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 

Xem thêm chi tiết tại địa chỉ: https://explainextended.com/2009/07/24/mysql-grouping-continuous-ranges/

Các vấn đề liên quan