2017-04-06 191 views
0

我有一個尷尬的情況,我有一個表存儲了隨時間變化的數據。在SQL查詢(MySQL)中選擇連續組中的最小值

我有一列groupId哪些組變成一個給定的值。我有value,它存儲的值更改爲,並且我有date它存儲更改發生的日期。

例如如果價值a應運而生的20000101和變化b20010101,我們可能會碰到這樣的:

+---------+-------+----------+ 
| groupId | value | date | 
+---------+-------+----------+ 
|  42 | a  | 20000101 | 
|  42 | b  | 20010101 | 
+---------+-------+----------+ 

現在把事情的樂趣,我們可以有哪些不值表示材料的變化如記錄

+---------+-------+----------+ 
| groupId | value | date | 
+---------+-------+----------+ 
|  43 | a  | 20000101 | 
|  43 | b  | 20010101 | 
|  43 | b  | 20020101 | 
+---------+-------+----------+ 

和額外的樂趣,我們可以有哪些更改到別的東西的值,然後又變回它以前一樣:

+---------+-------+----------+ 
| groupId | value | date | 
+---------+-------+----------+ 
|  44 | a  | 20000101 | 
|  44 | b  | 20010101 | 
|  44 | a  | 20020101 | 
+---------+-------+----------+ 

結合這些結合在一起,我們可以有一組看起來是這樣的:

+---------+-------+----------+ 
| groupId | value | date | 
+---------+-------+----------+ 
|  45 | a  | 20000101 | 
|  45 | a  | 20010101 | 
|  45 | b  | 20020101 | 
|  45 | b  | 20030101 | 
|  45 | a  | 20040101 | 
|  45 | a  | 20050101 | 
|  45 | b  | 20060101 | 
|  45 | b  | 20070101 | 
+---------+-------+----------+ 

我需要做的是編寫一個查詢將返回的行爲一組,但丟掉任何的那些非物質的變化。對於以上45組中,這意味着在返回:

+---------+-------+----------+ 
| groupId | value | date | 
+---------+-------+----------+ 
|  45 | a  | 20000101 | 
|  45 | b  | 20020101 | 
|  45 | a  | 20040101 | 
|  45 | b  | 20060101 | 
+---------+-------+----------+ 

即我們只保留的最早日期爲每個「連續」基團(的groupId ,,值)。

是否有任何合理的方法來實現這一目標?

我在MySQL中這樣做,雖然不依賴於此的解決方案將是理想的。

回答

0

使用this answer方法來模擬lag()在MySQL的:

SET @prev_value=''; 
select groupId, value, date 
from (
    select groupId, @prev_value prev_value, @prev_value :=value value, date 
    from t 
    order by groupId, date 
) a 
where prev_value <> value; 

rextester演示:http://rextester.com/PWF35736

回報:

+---------+-------+----------+ 
| groupId | value | date | 
+---------+-------+----------+ 
|  45 | a  | 20000101 | 
|  45 | b  | 20020101 | 
|  45 | a  | 20040101 | 
|  45 | b  | 20060101 | 
+---------+-------+----------+ 
0

首先,我們需要建立信息到表本身它告訴我們什麼時候改變是非常重要的。在這種情況下,我們知道當兩個相同的值在時間中出現時,記錄是不重要的。我們可以通過分配一個將非物質和物質記錄組合在一起的「等級」來做到這一點。假設我們的表稱爲A,下面的查詢:

select a1.groupID 
     , a1.value 
     , a1.date 
     , COUNT(a2.groupID) as Ranked 
    from A a1 
    left join A a2 
     on a2.groupID = a1.groupID 
     and a2.value <> a1.value 
     and a2.date < a1.date 
    group by a1.groupID 
      , a1.value 
      , a1.date 
    order by a1.date 

生成此表:

+ ------- + ----- + ---------- + ------ + 
| groupId | value | date  | Ranked | 
+ ------- + ----- + ---------- + ------ + 
| 45  | a  | 2000-01-01 | 0  | 
| 45  | a  | 2001-01-01 | 0  | 
| 45  | b  | 2002-01-01 | 2  | 
| 45  | b  | 2003-01-01 | 2  | 
| 45  | a  | 2004-01-01 | 2  | 
| 45  | a  | 2005-01-01 | 2  | 
| 45  | b  | 2006-01-01 | 4  | 
| 45  | b  | 2007-01-01 | 4  | 
+ ------- + ----- + ---------- + ------ + 

然後通過的groupId,價值分組和排名,我們可以選擇分鐘(日期)。由於MySQL不支持CTE的,我們只使用臨時表

create temporary table Ranking as (
    select a1.groupID 
      , a1.value 
      , a1.date 
      , COUNT(a2.groupID) as Ranked 
     from A a1 
     left join A a2 
      on a2.groupID = a1.groupID 
      and a2.value <> a1.value 
      and a2.date < a1.date 
     group by a1.groupID 
       , a1.value 
       , a1.date 
     order by a1.date 
) 

select groupId 
     , value 
     , min(date) as date 
    from Ranking 
    group by groupId 
      , value 
      , ranked 
    order by date 

,瞧,我們得到了想要的結果

+ ------- + ----- + ---------- + 
| groupId | value | date  | 
+ ------- + ----- + ---------- + 
| 45  | a  | 2000-01-01 | 
| 45  | b  | 2002-01-01 | 
| 45  | a  | 2004-01-01 | 
| 45  | b  | 2006-01-01 | 
+ ------- + ----- + ---------- +