2013-04-24 3 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 не поддерживает окна функции, как и любой другой РСУБД делает, вы можете моделировать, как вы можете создать последовательные номера и использовать в качестве столбца, ссылающейся на получить предыдущие строки. Ex,

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

+0

Но может быть легко адаптирован для работы с несколькими идентификаторами – Strawberry

+0

@Andomar права. –

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

Но они этого не делают. ОП сказал это. – Strawberry

+0

"Примечание. Номера версий не гарантируются последовательностью, начиная с 1." – mellamokb

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

+0

@mellamokb, извините, неверно сформулировал вопрос. –

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 
Смежные вопросы