2014-01-30 27 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 | 
    +----+--------+---------+---------------------+------+------+ 

第三和最后一部分是故意留下作为一个练习的读者,但是,这种解决方案的一个缺点是,它不适合特别好。