Выберите 3 самые последние записи, в которых значения одного столбца различны - PullRequest
45 голосов
/ 29 мая 2009

У меня есть следующая таблица:

    id       time      text      otheridentifier
    -------------------------------------------
    1        6         apple     4
    2        7         orange    4
    3        8         banana    3
    4        9         pear      3
    5        10        grape     2

Что я хочу сделать, это выбрать 3 самые последние записи (по времени), чьи otheridentifier различны. Так что в этом случае результат будет id: 5, 4 и 2.

id = 3 будет пропущено, поскольку есть более поздняя запись с тем же полем otheridentifier.

Вот что я пытался сделать:

SELECT * FROM `table` GROUP BY (`otheridentifier`) ORDER BY `time` DESC LIMIT 3

Однако в итоге я получаю строки id = 5, 3 и 1 вместо 5, 4, 2, как и ожидалось.

Может кто-нибудь сказать мне, почему этот запрос не вернул то, что я ожидал? Я попытался изменить ORDER BY на ASC, но это просто переставило возвращаемые строки в 1, 3, 5.

Ответы [ 8 ]

34 голосов
/ 29 мая 2009

Он не возвращает того, что вы ожидаете, потому что группировка происходит перед упорядочением, что отражается положением предложений в операторе SQL. Тебе, к сожалению, придётся повеселиться, чтобы получить нужные тебе строки. Попробуйте это:

SELECT *
FROM `table`
WHERE `id` = (
    SELECT `id`
    FROM `table` as `alt`
    WHERE `alt`.`otheridentifier` = `table`.`otheridentifier`
    ORDER BY `time` DESC
    LIMIT 1
)
ORDER BY `time` DESC
LIMIT 3
18 голосов
/ 29 мая 2009

Вы можете присоединиться к самой таблице, чтобы отфильтровать последнюю запись для otheridentifier, а затем взять верхние 3 строки этого:

SELECT last.*
FROM `table` last
LEFT JOIN `table` prev 
    ON prev.`otheridentifier` = last.`otheridentifier`
    AND prev.`time` < last.`time`
WHERE prev.`id` is null
ORDER BY last.`time` DESC 
LIMIT 3
4 голосов
/ 30 апреля 2013

У меня было похожее требование, но у меня были более продвинутые критерии отбора. Используя некоторые другие ответы, я не смог получить именно то, что мне было нужно, но я обнаружил, что вы можете сделать GROUP BY после и ORDER BY следующим образом:

SELECT t.* FROM (SELECT * FROM table ORDER BY time DESC) t 
GROUP BY t.otheridentifier
2 голосов
/ 08 января 2014

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

SELECT * FROM 
      (SELECT * FROM `table` order by time DESC)
          t group by otheridentifier
2 голосов
/ 29 мая 2009

Ответ Andomar , вероятно, лучше всего в том, что он не использует подзапрос.

Альтернативный подход:

select *
from   `table` t1
where  t1.`time` in (
                    select   max(s2.`time`)
                    from     `table` t2
                    group by t2.otheridentifier
                    )
2 голосов
/ 29 мая 2009
SELECT * FROM table t1 
WHERE t1.time = 
    (SELECT MAX(time) FROM table t2 
     WHERE t2.otheridentifier = t1.otheridentifier)
1 голос
/ 29 февраля 2012

а как же

SELECT *, max(time) FROM `table`  group by otheridentifier
0 голосов
/ 15 июня 2016

Это также:

SELECT * FROM
OrigTable T INNER JOIN 
( 
SELECT otheridentifier,max(time) AS duration
FROM T
GROUP BY otheridentifier) S
ON S.duration = T.time AND S.otheridentifier = T.otheridentifier.
...