MySQL-управление, какая строка возвращается группой по



у меня есть таблица базы данных, как это:



id    version_id    field1    field2
1 1 texta text1
1 2 textb text2
2 1 textc text3
2 2 textd text4
2 3 texte text5


Если вы не разработали его, он содержит несколько версий строки, а затем некоторые текстовые данные.



Я хочу запросить его и вернуть версию с наибольшим числом для каждого идентификатора. (так что вторая и последняя строки только в приведенном выше).



Я пробовал использовать group by при заказе по version_id DESC-но он, кажется, заказывает после его группировки, поэтому это не работает.



у кого-нибудь есть идеи? Я не могу поверить, что это невозможно!



обновление:



придумайте это, что работает, но использует подзапрос:



SELECT *
FROM (SELECT * FROM table ORDER BY version_id DESC) t1
GROUP BY t1.id
601   9  

9 ответов:

это называется выбором группового максимума столбца. вот несколько различных подходов для MySQL.

вот как я бы сделал это:

SELECT *
FROM (SELECT id, max(version_id) as version_id FROM table GROUP BY id) t1
INNER JOIN table t2 on t2.id=t1.id and t1.version_id=t2.version_id

Это будет относительно эффективно, хотя mysql создаст временную таблицу в памяти для подзапроса. Я предполагаю, что у вас уже есть индекс (id, version_id) для этой таблицы.

это недостаток в SQL, что вы более или менее должны использовать подзапрос для этого типа проблемы (полу-присоединяется к другой пример).

подзапросы не очень хорошо оптимизированы в mysql, но некоррелированные подзапросы не так уж плохи, пока они не настолько огромны, что они будут записываться на диск, а не в память. Учитывая, что в этом запросе есть только два int, подзапрос может составлять миллионы строк задолго до этого, но подзапрос select * в вашем первом запросе может пострадать от этой проблемы намного раньше.

Я думаю, что это сделает это, не уверен, что это лучший или самый быстрый, хотя.

SELECT * FROM table 
WHERE (id, version_id) IN 
  (SELECT id, MAX(version_id) FROM table GROUP BY id)
SELECT id, version_id, field1, field2
FROM (
    SELECT @prev = id AS st, (@prev := id), m.*
    FROM (
           (SELECT @prev := NULL) p,
           (
            SELECT *
            FROM   mytable
            ORDER BY
                   id DESC, version_id DESC
           ) m
     ) m2
WHERE NOT IFNULL(st, FALSE);

нет подзапросов, один проход на UNIQUE INDEX ON MYTABLE (id, version_id) если у вас есть один (который я думаю, вы должны)

обычно я делаю это с подзапросом:

выберите ID, version_id, поле1, поле2 из DataTable в качестве ДТ где ID = (выберите ID из объекта DataTable, где ID = ДТ.id заказа путем ограничения version_id убыв 1)

это псевдо-код, но что-то вроде этого должно работать нормально

select *
from table
inner join
(
    select id , max(version_id) maxVersion
    from table 
) dvtbl ON id = dvtbl.id && versionid = dvtbl.maxVersion

этот запрос будет выполнять работу без группы by:

SELECT * FROM table AS t
LEFT JOIN table AS t2 
    ON t.id=t2.id 
    AND t.version_id < t2.version_id
WHERE t2.id IS NULL

ему не нужны никакие временные таблицы.

всегда можно перейти к аналитическим функциям, которые дадут вам больше контроля

select tmp.* from ( select id,version_id,field1,field2, rank() over(partition by id order by version_id desc ) as rnk from table) tmp where tmp.rnk=1

Если вы столкнулись с проблемой с функцией rank() в зависимости от типа данных, то можно выбрать из row_number() или dense_rank () тоже.

Я думаю, что это то, что вы хотите.

select id, max(v_id), field1, field2 from table group by id

результаты, которые я получаю, являются

1, 2, textb, text2

2, 3, texte, text5

Edit: Я воссоздал таблицу и вставил те же данные с идентификатором version_id, являющимся составным первичным ключом. Это дало ответ, который я дал ранее. Это было также в MySQL.

Не проверял, но что-то подобное может работать:

выберите * из группы таблиц по порядку id по MAX (version_id) DESC

Comments

    Ничего не найдено.