Как я могу отфильтровать несколько повторений в MySQL Query - PullRequest
0 голосов
/ 27 января 2020

У меня есть таблица mysql, как показано ниже. Он использовался для хранения документов с версиями.

enter image description here

Я хочу выбрать документ из последних (с самой высокой основной версией и второстепенной версией). Он будет уничтожать все те же идентификаторы c, которые будут извлекать только документ с наивысшими значениями major_version и minor_version. Так что я хочу результат, как показано ниже.

enter image description here

Ответы [ 2 ]

1 голос
/ 27 января 2020

В MySQL 8.0 вы можете фильтровать с помощью row_number():

select *
from (
    select 
        t.*, 
        row_number() over(partition by id, docid order by major_version, minor_version) rn
    from mytable t
) t
where rn = 1

В более ранних версиях вы можете фильтровать с помощью коррелированного подзапроса. Предполагая, что у вас есть первичный ключ в таблице, скажем, столбец pk, вы можете сделать:

select t.*
from mytable t
where t.pk = (
    select t1.pk
    from mytable t1
    where t1.id = t.id and t1.docid = t.docid
    order by t1.major_version desc, t1.minor_version desc 
    limit 1
)

Для производительности рассмотрите индекс на (id, docid, major_version, minor_version).

Без уникального Столбец, который можно использовать в качестве первичного ключа, немного сложнее. Один из способов сделать это - использовать not exists:

select t.*
from mytable t
where not exists (
    select 1 
    from mytable t1 
    where 
        t1.id = t.id 
        and t1.docid = t.docid
        and (
            t1.major_version > t.major_version
            or (t1.major_version = t.major_version and t1.minor_version > t.minor_version)
        )
)
0 голосов
/ 27 января 2020

Один метод использует row_number():

select t.*
from (select t.*,
             row_number() over (partition by docid order by major_version desc, minor_version desc) as seqnum
      from t
     ) t
where seqnum = 1;

Это боль в более ранних версиях. Вероятно, самый простой и эффективный метод - использовать переменные:

select t.*
from (select t.*,
             (@rn := if(@d = docid, @rn + 1,
                        if(@d := docid, 1, 1)
                       )
             ) as rn
      from (select t.*
            from t
            order by docid, major_version desc, minor_version desc
           ) t cross join
           (select @rn := 0, @d := '') params
     ) t
where rn = 1;
...