SELECT LIMIT 1 для каждого значения столбца?

11

Допустим, у меня есть следующая таблица

-----------------------------
| user_id   | comment       |
-----------------------------
| 2         | thats cool    |
| 2         | awesome       |
| 3         | i hate this   |
| 3         | okay          |
| 6         | this is weird |
| 6         | hello?        |
| 6         | what is it    |
| 9         | how are you   |
| 16        | too slow      |
| 16        | yes           |
| 17        | alrighty      |
-----------------------------

Как вы можете выбрать один ряд на user_id? Так что мои результаты будут:

-----------------------------
| user_id   | comment       |
-----------------------------
| 2         | thats cool    |
| 3         | i hate this   |
| 6         | this is weird |
| 9         | how are you   |
| 16        | too slow      |
| 17        | alrighty      |
-----------------------------

Возможно ли это с помощью одного эффективного запроса? Или подвыбор необходим? Можно ли как-то использовать DISTINCTодин столбец?

Джейк Уилсон
источник

Ответы:

9

Это то, что GROUP BYиспользуется для. Получите один ряд (на группу). В этом случае он будет показывать все различные user_idзначения и для остальных столбцов, вы можете (должны) использовать агрегатные функции , такие как MIN(), MAX(), AVG(), SUM()как вы будете иметь более одного значения для каждой группы и может быть показан только один.

SELECT
    user_id
  , MIN(comment) AS comment  -- it will show the first in alphabetical order  
                             -- you could also use MAX()
FROM
    tableX
GROUP BY
    user_id ;

MySQL также допускает следующее неортодоксальное решение, которое будет возвращать один (более или менее случайный) комментарий на пользователя:

SELECT
    user_id
  , comment
FROM
    tableX
GROUP BY
    user_id ;

Этот последний запрос не будет работать, но вызовет ошибку, если ONLY_FULL_GROUP_BYвключен (более строгий) режим. В недавно выпущенной версии 5.7 этот режим используется по умолчанию и предоставляется новая функция ANY_VALUE(). Для получения более подробной информации см. Раздел «Обработка MySQL»GROUP BY . Запрос можно написать сейчас:

SELECT
    user_id
  , ANY_VALUE(comment) AS comment
FROM
    tableX
GROUP BY
    user_id ;

Обратите внимание, что при использовании «неортодоксальной» версии или использовании недавней ANY_VALUE()функции, если мы добавим больше столбцов в SELECTсписок, их значения не обязательно будут из одной строки, только из строки в той же группе. Способ их выбора не является абсолютно случайным, зависит от плана выполнения и используемых индексов.

ypercubeᵀᴹ
источник
Есть ли другие способы указать, какая строка будет извлечена для user_id? Любой способ указать вид ORDER BY?
Джейк Уилсон
Кроме того, MINа MAX?
ypercubeᵀᴹ
1
Тогда это сложнее. Посмотрите этот другой вопрос: MySQL Query - Как получить самые последние демографические данные?
ypercubeᵀᴹ
2
Вы также найдете массу подобных проблем на SO сайте под [greatest-n-per-group]тегом.
ypercubeᵀᴹ
1
@ T.BrianJones Вы имеете в виду в «неортодоксальном» запросе, добавляете ли вы все остальные столбцы в список SELECT? Это первое, они могут быть не из одного ряда. Это не совсем случайно, но значения могут быть из разных строк (из одной группы).
ypercubeᵀᴹ