2014-01-30 61 views
1

我有這樣的一個表:查詢變化

id | status | user_id | created_at 
---:--------:---------:-------------------- 
1 | 0 |  1 | 2014-01-05 07:23:15 
2 | 1 |  1 | 2014-01-05 07:23:16 
3 | 1 |  1 | 2014-01-05 07:23:17 
4 | 0 |  1 | 2014-01-05 07:23:18 
5 | 0 |  1 | 2014-01-05 07:23:19 
6 | 1 |  1 | 2014-01-05 07:23:20 
7 | 0 |  2 | 2014-01-05 07:23:21 
8 | 0 |  1 | 2014-01-05 07:23:22 
9 | 0 |  2 | 2014-01-05 07:23:23 
10 | 1 |  2 | 2014-01-05 07:23:24 
11 | 0 |  2 | 2014-01-05 07:23:25 
12 | 1 |  2 | 2014-01-05 07:23:26 

我想查詢的status場的變化,由user_id分組,總是取最後的狀態(基於created_at)。查詢的結果應該是這樣的:

id | status | user_id | created_at 
---:--------:---------:-------------------- 
1 | 0 |  1 | 2014-01-05 07:23:15 
3 | 1 |  1 | 2014-01-05 07:23:17 
5 | 0 |  1 | 2014-01-05 07:23:19 
6 | 1 |  1 | 2014-01-05 07:23:20 
8 | 0 |  1 | 2014-01-05 07:23:22 
9 | 0 |  2 | 2014-01-05 07:23:23 
10 | 1 |  2 | 2014-01-05 07:23:24 
11 | 0 |  2 | 2014-01-05 07:23:25 
12 | 1 |  2 | 2014-01-05 07:23:26 

有沒有一種方法來查詢在這樣的情況下在SQL變化?如何寫這個查詢?

+0

是的。如果id列是連續的(沒有空白),那麼這很容易。如果有差距,那就稍微困難一點。無論哪種方式,都必須在SO(和其他地方)提供很多解決方案。 – Strawberry

+0

你有什麼例子嗎? –

回答

1

在這種情況下,在MySQL中使用變量可能是一個好主意。

以下是一個快速嘗試,詳細闡述步驟。清理並調整它以適應要求和性能。

select id, status, user_id, created_at from 
(select id, status, user_id, created_at, 
     (case when @user_id != user_id then 'true' else 'false' end) as user_changed, 
     (case when @status != status then 'true' else 'false' end) as status_changed, 
     (case when @user_id != user_id then @user_id := user_id end) as new_user_id, 
     (case when @status != status then @status := status end) as new_status 
    from (select * from logs order by user_id asc, created_at desc) l 
    join (select @user_id := 0) u 
    join (select @status := 0) s) q 
where user_changed = 'true' or status_changed = 'true' 
order by id 
; 
+0

http://sqlfiddle.com/#!2/89f85/11 –

2

考慮以下...

DROP TABLE IF EXISTS my_table; 

CREATE TABLE my_table 
(id INT NOT NULL AUTO_INCREMENT PRIMARY KEY 
,status TINYINT NOT NULL DEFAULT 1 
,user_id INT NOT NULL 
,created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP 
); 

INSERT INTO my_table VALUES 
(1 , 0 , 1 ,'2014-01-05 07:23:15'), 
(2 , 1 , 1 ,'2014-01-05 07:23:16'), 
(3 , 1 , 1 ,'2014-01-05 07:23:17'), 
(4 , 0 , 1 ,'2014-01-05 07:23:18'), 
(5 , 0 , 1 ,'2014-01-05 07:23:19'), 
(6 , 1 , 1 ,'2014-01-05 07:23:20'), 
(7 , 0 , 2 ,'2014-01-05 07:23:21'), 
(8 , 0 , 1 ,'2014-01-05 07:23:22'), 
(9 , 0 , 2 ,'2014-01-05 07:23:23'), 
(10 , 1 , 2 ,'2014-01-05 07:23:24'), 
(11 , 0 , 2 ,'2014-01-05 07:23:25'), 
(12 , 1 , 2 ,'2014-01-05 07:23:26'); 

對於提供低於它實際上並不重要,該ID是連續的解決方案,只是它的順序。我已經打破瞭解決方案分解成位,所以你可以看到它在做什麼......

,第一部分由排名用戶結果...

SELECT x.* 
    , COUNT(*) rank 
    FROM my_table x 
    JOIN my_table y 
    ON y.user_id = x.user_id 
    AND y.id <= x.id 
GROUP 
    BY x.id 
ORDER 
    BY x.user_id,rank; 

    +----+--------+---------+---------------------+------+ 
    | id | status | user_id | created_at   | rank | 
    +----+--------+---------+---------------------+------+ 
    | 1 |  0 |  1 | 2014-01-05 07:23:15 | 1 | 
    | 2 |  1 |  1 | 2014-01-05 07:23:16 | 2 | 
    | 3 |  1 |  1 | 2014-01-05 07:23:17 | 3 | 
    | 4 |  0 |  1 | 2014-01-05 07:23:18 | 4 | 
    | 5 |  0 |  1 | 2014-01-05 07:23:19 | 5 | 
    | 6 |  1 |  1 | 2014-01-05 07:23:20 | 6 | 
    | 8 |  0 |  1 | 2014-01-05 07:23:22 | 7 | 
    | 7 |  0 |  2 | 2014-01-05 07:23:21 | 1 | 
    | 9 |  0 |  2 | 2014-01-05 07:23:23 | 2 | 
    | 10 |  1 |  2 | 2014-01-05 07:23:24 | 3 | 
    | 11 |  0 |  2 | 2014-01-05 07:23:25 | 4 | 
    | 12 |  1 |  2 | 2014-01-05 07:23:26 | 5 | 
    +----+--------+---------+---------------------+------+ 

第二部分加入這個查詢本身,亮點異常...

SELECT a.* 
    , b.id 
    FROM 
    (SELECT x.* 
      , COUNT(*) rank 
     FROM my_table x 
     JOIN my_table y 
      ON y.user_id = x.user_id 
      AND y.id <= x.id 
     GROUP 
      BY x.id 
    ) a 
LEFT 
JOIN 
    (SELECT x.* 
       , COUNT(*) rank 
      FROM my_table x 
      JOIN my_table y 
      ON y.user_id = x.user_id 
      AND y.id <= x.id 
      GROUP 
      BY x.id 
    ) b 
    ON b.user_id = a.user_id 
    AND b.status = a.status 
    AND b.rank = a.rank + 1; 


    +----+--------+---------+---------------------+------+------+ 
    | id | status | user_id | created_at   | rank | id | 
    +----+--------+---------+---------------------+------+------+ 
    | 1 |  0 |  1 | 2014-01-05 07:23:15 | 1 | NULL | 
    | 2 |  1 |  1 | 2014-01-05 07:23:16 | 2 | 3 | 
    | 3 |  1 |  1 | 2014-01-05 07:23:17 | 3 | NULL | 
    | 4 |  0 |  1 | 2014-01-05 07:23:18 | 4 | 5 | 
    | 5 |  0 |  1 | 2014-01-05 07:23:19 | 5 | NULL | 
    | 6 |  1 |  1 | 2014-01-05 07:23:20 | 6 | NULL | 
    | 7 |  0 |  2 | 2014-01-05 07:23:21 | 1 | 9 | 
    | 8 |  0 |  1 | 2014-01-05 07:23:22 | 7 | NULL | 
    | 9 |  0 |  2 | 2014-01-05 07:23:23 | 2 | NULL | 
    | 10 |  1 |  2 | 2014-01-05 07:23:24 | 3 | NULL | 
    | 11 |  0 |  2 | 2014-01-05 07:23:25 | 4 | NULL | 
    | 12 |  1 |  2 | 2014-01-05 07:23:26 | 5 | NULL | 
    +----+--------+---------+---------------------+------+------+ 

第三和最後一部分是故意留下作爲一個練習的讀者,但是,這種解決方案的一個缺點是,它不適合特別好。