MySQL

2012-09-05 10 views
7

kullanarak sürekli aralıklar nasıl gruplanır? Kategoriler, tarihler ve oranlar içeren bir tablom var. Her kategori farklı tarihler için farklı ücretlere sahip olabilir, bir kategori belirli bir tarihte yalnızca bir orana sahip olabilir.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 

Benzersiz indeksi (CatID, Tarih, Oranı) Ben grubun tüm sürekli tarih aralıkları için her bir kategori için mi sadece başlar ve Aralığın sonu tutacak. Önceki Örneğin , biz olurdu:

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 

Tam

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 

ben Mysql'de aynı şeyi yapabilir Nasıl SQL FIDDLE SEE bir sonuç vermedi the forum benzer bir çözüm buldu ? Lütfen yardım edin!

+0

Neden ((CatID, Oranı) = 'için örnek neleri gösterir 14,1) '2009-07-08' ile 2009-07-10 arası bir sonuç, altta yatan tabloda' 2009-07-09' yokken? Bakınız: Süreksizlik nedeniyle iki sonuç aralığı üreten '(CatId, Rate) = (12,1)'. – eggyal

+0

Teşekkürler eggyal, şimdi düzeltildi – Fouzi

cevap

6

MySQL analitik fonksiyonlar desteklemez, ancak user-defined variables böyle davranışını taklit edebilirsiniz:

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 üzerine bakın.

+0

Beklendiği gibi çalışıyor! Çok teşekkürler yumurtalı! – Fouzi

+1

'<=>' nedir? –

+1

@vanabel: Bu MySQL'in [NULL-safe operatöre eşittir] 'dir (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 

Not: hattı (: = -1, @rn: = 0, @prev_id: = 0, @ prev_date: @prev SEÇ = - 1) MySQL çalışma alanı gerekli değildir değişkenler AS ama PHP mysql_query işlevindedir.

SQL FIDDLE HERE

+0

Eğer kayıt = ID = '000004' sorgu geri dönüş ile kaldırılırsa (başlar: 2009-07-07, son: 2009-07-16, oran: 1) bu doğru değil çünkü boşluk, geri dönmelidir (başlangıç: 2009-07-07, bitiş tarihi: 2009-07-09, oran: 1) ve (başlangıç: 2009-07-15, bitiş: 2009-07-16, oran: 1). [SQL FIDDLE HERE] (http://sqlfiddle.com/#!2/513b2/1) – Fouzi

+0

@BoussahelBachir, cevabı düzenledim. Bu durumda, bahsettiğiniz duruma hitap etmek için tarihçinin durumunu eklemeniz gerekir. – sel

+0

Hiçbir yerde '@ prev_id' test edilmiyor gibi görünüyorsun ... aynı" Rate "ile iki bitişik tarihin farklı bir' CatId 'olması durumunda ne olur? – eggyal

0

Geç kaldığımı biliyorum, hala benim için çalışan bir çözüm yolladım. burada

de değişkenler

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 

Daha bilgilerini kullanarak iyi bir çözüm Bulunan aldım nasıl, aynı sorunu vardı: https://explainextended.com/2009/07/24/mysql-grouping-continuous-ranges/