2013-04-24 94 views
1

我有以下结构的SQL表:SQL查询前值的每一行

id Integer, (represents a userId) 
version Integer, 
attribute varchar(50) 

所以一些样本行是:

4, 1, 'test1' 
4, 2, 'test2' 
4, 3, 'test3' 

我需要生成以下格式输出:

4, 1, 'test1', 'test1' 
4, 2, 'test2', 'test1' 
4, 3, 'test3', 'test2' 

所以我输出的格式是:

id Integer, 
version Integer, 
attribute_current varchar, 
attribute_old varchar 

我已经试过如下:

select versionTest.id, versionTest.version, versionTest.attribute, maxVersionTest.attribute 
from versionTest 
inner join 
versionTest maxVersionTest 
ON 
versionTest.id = versionTest.id 
AND 
versionTest.version = 
(Select max(version) currentMaxVersion 
from versionTest maxRow 
where maxRow.id = id); 

上面的查询执行,但返回不正确的结果。它只返回最大版本,而不是返回所有版本的行。

约我应该怎么解决我的查询产生正确的结果任何想法?谢谢!

注 - 版本号,但不保证顺序从1开始的我实际的数据库中有一些不寻常的版本号(即用户7有3版和第15版没有4,5,6,等...) 。

回答

1
SELECT a.*, COALESCE(b.attribute,a.attribute) attribute_old 
    FROM 
    (SELECT x.* 
      , COUNT(*) rank 
     FROM versiontest x 
     JOIN versiontest y 
      ON y.id = x.id 
      AND y.version <= x.version 
     GROUP 
      BY x.id 
      , x.version 
    ) a 
    LEFT 
    JOIN 
    (SELECT x.* 
      , COUNT(*) rank 
     FROM versiontest x 
     JOIN versiontest y 
      ON y.id = x.id 
      AND y.version <= x.version 
     GROUP 
      BY x.id 
      , x.version 
    ) b 
    ON b.id = a.id 
    AND b.rank = a.rank-1; 

样本输出(DEMO):

+----+---------+-----------+------+---------------+ 
| id | version | attribute | rank | attribute_old | 
+----+---------+-----------+------+---------------+ 
| 4 |  1 | test1  | 1 | test1   | 
| 4 |  5 | test2  | 2 | test1   | 
| 4 |  7 | test3  | 3 | test2   | 
| 5 |  2 | test3  | 1 | test3   | 
| 5 |  3 | test4  | 2 | test3   | 
| 5 |  8 | test5  | 3 | test4   | 
+----+---------+-----------+------+---------------+ 
1

既然你已经提到:

版本号并不能保证在1我实际的数据库是连续的起点有一些不寻常的版本号(即用户7有3版和第15版无4,5,6,等...)

MySQL不支持像任何其他RDBMS窗口功能呢,你仍然可以模拟你如何创建一个序列号,并作为连接列获取以前的行。当然,

SELECT a.ID, a.Version, a.attribute attribute_new, 
     COALESCE(b.attribute, a.attribute) attribute_old 
FROM 
     (
      SELECT ID, version, attribute, 
        @r1 := @r1 + 1 rn 
      FROM TableName, (SELECT @r1 := 0) b 
      WHERE ID = 4 
      ORDER BY version 
     ) a 
     LEFT JOIN 
     (
      SELECT ID, version, attribute, 
        @r2 := @r2 + 1 rn 
      FROM TableName, (SELECT @r2 := 0) b 
      WHERE ID = 4 
      ORDER BY version 
     ) b ON a.rn = b.rn + 1 
+1

这如果op是查询单个ID – Andomar 2013-04-24 13:19:16

+0

但可以很容易地适应用多个ID – Strawberry 2013-04-24 13:22:56

+0

@Andomar工作权工作。 – 2013-04-24 13:23:26

0

如果版本号总是1增加,你可以:

select cur.id 
,  cur.version 
,  cur.attribute 
,  coalesce(prev.attribute, cur.attribute) 
from versionTest 
left join 
     versionTest prev 
on  prev.id = cur.id 
     and prev.version = cur.version + 1 
+1

但他们没有。该OP这么说。 – Strawberry 2013-04-24 13:18:25

+0

“注 - 版本号,但不保证顺序从1开始” – mellamokb 2013-04-24 13:18:33

0

你可以试试...

SELECT ID, 
     VERSION, 
     ATTRIBUTE, 
     (SELECT ATTRIBUTE 
      FROM VERSIONTEST V3 
      WHERE V3.ID = V1.ID AND 
        V3.VERSION = (SELECT MAX(VERSION) 
            FROM VERSIONTEST V2 
            WHERE V2.ID = V1.ID AND 
              V2.VERSION < V1.VERSION)) AS PREVIOUSATTRIBUTE 
    FROM VERSIONTEST V1; 

提供的版本值是按数字顺序排列。

+0

这得到以前的版本号,但*不*实际属性的先前版本:http://www.sqlfiddle.com/#!2/defc0/8 – mellamokb 2013-04-24 13:41:26

+0

@mellamokb,对不起,误解的问题。 – 2013-04-24 13:47:56

0

我想表达这种最简单的方法是用相关子查询:

select id, version, attribute as attribute_current, 
     (select attribute 
     from VersionTest vt2 
     where vt2.id = vt.id and vt2.version < vt.version 
     order by vt2.version 
     limit 1 
     ) as attribute_prev 
from VersionTest vt 

该版本将放在NULL为第一行的上一个值。如果你真的想重复:

select id, version, attribute as attribute_current, 
     coalesce((select attribute 
       from VersionTest vt2 
       where vt2.id = vt.id and vt2.version < vt.version 
       order by vt2.version 
       limit 1 
       ), vt.attribute 
       ) as attribute_prev 
from VersionTest vt