SELECIONAR LIMITE 1 por valor da coluna?

10

Vamos dizer que tenho a tabela a seguir

-----------------------------
| 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      |
-----------------------------

Como você pode selecionar uma linha por user_id? Então, meus resultados seriam:

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

Isso é possível com uma única consulta eficiente? Ou são sub-selecionados necessários? É possível usar de alguma forma DISTINCTem uma única coluna?

Jake Wilson
fonte

Respostas:

9

É para isso que GROUP BYé usado. Obtenha uma linha (por grupo). Neste caso, ele irá mostrar todos os distintos user_idvalores e para o resto das colunas, pode (ter a) utilizar as funções de agregação como MIN(), MAX(), AVG(), SUM()à medida que vai ter mais do que um valores por grupo e apenas um pode ser mostrado.

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 ;

O MySQL também permite a seguinte solução não ortodoxa, que retornará um comentário (mais ou menos aleatório) por usuário:

SELECT
    user_id
  , comment
FROM
    tableX
GROUP BY
    user_id ;

Esta última consulta não funcionará, mas gerará um erro se o modo (mais rigoroso) ONLY_FULL_GROUP_BYestiver ativado. Na versão 5.7 lançada recentemente, esse modo é o padrão e uma nova função ANY_VALUE()é fornecida. Para mais detalhes, consulte a página MySQL HandlingGROUP BY . A consulta pode ser gravada agora:

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

Observe que, com a versão "não ortodoxa" ou usando a ANY_VALUE()função recente , se adicionarmos mais colunas na SELECTlista, não é garantido que seus valores sejam da mesma linha, apenas de uma linha do mesmo grupo. A maneira como são selecionados não é exatamente aleatória, depende do plano de execução e dos índices utilizados.

ypercubeᵀᴹ
fonte
Existem outras maneiras de especificar qual linha é puxada para um user_id? Alguma maneira de especificar um tipo de ORDER BY?
Jake Wilson
Além MINe MAX?
precisa saber é o seguinte
11
Então é mais complexo. Veja esta outra pergunta: Consulta MySQL - Como obter dados demográficos mais recentes?
usar o seguinte código
2
Você também encontrará vários problemas semelhantes no site SO, abaixo da [greatest-n-per-group]tag.
usar o seguinte código
11
@ T.BrianJones, você quer dizer na consulta "não ortodoxo", se você adicionar todas as outras colunas na lista SELECT? É o primeiro, eles podem não ser da mesma linha. Não é exatamente aleatório, mas os valores podem ser de linhas diferentes (do mesmo grupo).
ypercubeᵀᴹ