2016-09-25 52 views
2

假設我有一個表,看起來像:基於前一個和下排的MySQL選擇行

  mytable 
category |  begintime 
---------|---------------------- 
cat1  | 2016-09-25 15:00:00 
cat2  | 2016-09-25 16:00:00 
cat1  | 2016-09-25 17:30:00 
cat3  | 2016-09-25 19:00:00 
cat1  | 2016-09-25 20:00:00 
    :     : 

注意,它沒有一個ID號,begintime列是我的主鍵。最後,我想選擇被某個類別包圍的所有行,即選擇所有行,使得前一行的類別爲@catBefore,下一行的類別爲@catAfter

例如,我想是這樣的:導致

SELECT * FROM ... 
category |  begintime 
---------|---------------------- 
cat2  | 2016-09-25 16:00:00 
cat3  | 2016-09-25 19:00:00 
    :     : 

previousRownextRow在此

SELECT * FROM mytable WHERE previousRow.category = 'cat1' AND nextRow.category = 'cat1' 

,似乎並沒有被定義。

理念

我嘗試過的一些事情,但沒有奏效出來呢。我的一個想法是,先選擇一個和下一個類別作爲新列,所以像:

SELECT mytable.*, 
     previousRow.category AS prevCat, 
     nextRow.category AS nextCat 
FROM mytable, [stuff-I-don't-know] 

導致

 SELECT mytable.* ... 
category |  begintime  | prevCat | nextCat 
---------|----------------------|---------|--------- 
cat1  | 2016-09-25 15:00:00 | null | cat2 
cat2  | 2016-09-25 16:00:00 | cat1 | cat1 
cat1  | 2016-09-25 17:30:00 | cat2 | cat3 
cat3  | 2016-09-25 19:00:00 | cat1 | cat1 
cat1  | 2016-09-25 20:00:00 | cat3 | ... 
    :     : 

,然後用WHERE條款過濾。

這個想法是可能的,還是可以用其他方式完成?

+0

是否要查詢整個表,使這些prev和下一個類別和過濾呢? –

+0

假設你的前四行來自'cat1' ...如果你正在尋找prev和下一個等於'cat1',你應該只返回第二條記錄還是應該返回第三條記錄? –

+0

@FelyppOliveira如果是這樣的話,那麼第二和第三條記錄的前後都是'cat1',因此都應該返回 – konewka

回答

1

一種方法使用相關的子查詢。這應該是沒關係的性能,明智的,如果你確實有主鍵聲明:

select t.* 
from (select t.*, 
      (select t2.category 
       from mytable t2 
       where t2.begintime < t.begintime 
       order by begintime desc 
       limit 1 
      ) as prev_category,   
      (select t2.category 
       from mytable t2 
       where t2.begintime > t.begintime 
       order by begintime asc 
       limit 1 
      ) as next_category 
    from mytable t 
) t 
where prev_category = @cat1 and next_category = @cat2; 

編輯:

你可以用變量做到這一點:

select t.* 
from (select t.*, 
      (@pn := (case when (@pcy := @pn) = NULL then -1 -- never gets here 
          when (@pn := category) = NULL then -1 -- never gets here 
          else @pcy 
         end) 
        ) as next_category 
     from (select t.*, 
        (@pc := (case when (@pcx := @pc) = NULL then -1 -- never gets here 
           when (@pc := category) = NULL then -1 -- never gets here 
           else @pcx 
          end) 
        ) as prev_category 
      from t cross join 
       (select @pc := '') params 
      order by t.begintime 
      ) t cross join 
      (select @pn := '') params 
     order by t.begintime desc 
    ) t 
where prev_category = @cat1 and next_category = @cat2; 
+0

在你的子查詢中增加'Limit 1',否則這會拋出錯誤'sub query返回不止一行' –

+0

我也正在評論這一點。然而它的表現並不快,但這可能是由於我的桌子很大。它已經運行了幾分鐘,現在沒有返回任何東西。我可以輕易地限制這個前1000行左右,看看它是否確實有效嗎? – konewka

+0

@ konewka。 。 。是的,你可以在外部查詢中添加一個'limit'來查看它是如何工作的。你確實有'begintime'的索引嗎? –

1

我這樣做的..它似乎工作,但它實際上似乎太慢... = \我會盡力改善它。請檢查它是否適用於您:

SELECT 
    t1.category, 
    t1.begintime 
FROM myTable t1 -- current 
INNER JOIN myTable t2 ON 1=1 -- prev 
    AND t2.begintime < t1.begintime 
INNER JOIN myTable t3 ON 1=1 -- next 
    AND t3.begintime > t1.begintime 
LEFT JOIN myTable t4 ON 1=1 -- between current and prev 
    AND t4.begintime < t1.begintime 
    AND t4.begintime > t2.begintime 
LEFT JOIN myTable t5 ON 1=1 -- between current and next 
    AND t5.begintime > t1.begintime 
    AND t5.begintime < t3.begintime 
WHERE 1=1 
    AND t2.category = 'cat1' -- prev cat 
    AND t3.category = 'cat1' -- next cat 
    AND t4.begintime IS NULL -- nothing between current and prev 
    AND t5.begintime IS NULL -- nothing between current and next 
; 
+0

它不會給我任何不幸的結果,它會執行,但沒有結果 – konewka

+0

我試過了,根據你的樣本數據得到了預期的結果,你會運行什麼樣的prev和next類?如果你的數據沒有任何分類前一個和下一個,預期的結果是一個空集...查詢可能運作良好...我認爲你的過濾器/數據不應該與任何匹配...你能提取其他樣本數據嗎? –

+0

看看:http://sqlfiddle.com/#!9/7f62d5/3 –