SQL查找每行的上一个值

时间:2013-04-24 13:08:36

标签: mysql 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等...)。

5 个答案:

答案 0 :(得分: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 :(得分: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         |
+----+---------+-----------+------+---------------+

答案 2 :(得分: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

答案 3 :(得分: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;

如果版本值按数字顺序排列。

答案 4 :(得分: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作为第一行的prev值。如果你真的想重复它:

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