A seguir, é apresentado o exemplo mais simples possível, embora qualquer solução deva ser dimensionada para o máximo de n resultados necessários:
Dada uma tabela como essa abaixo, com colunas de pessoa, grupo e faixa etária, como você obteria as 2 pessoas mais velhas de cada grupo? (Os laços dentro dos grupos não devem produzir mais resultados, mas fornecer os 2 primeiros em ordem alfabética)
+ -------- + ------- + ----- + | Pessoa Grupo | Idade + -------- + ------- + ----- + | Bob 1 | 32 | Jill 1 | 34 | Shawn 1 | 42 | Jake 2 29 | Paul 2 36 | Laura 2 39 + -------- + ------- + ----- +
Conjunto de resultados desejado:
+ -------- + ------- + ----- + | Shawn 1 | 42 | Jill 1 | 34 | Laura 2 39 | Paul 2 36 + -------- + ------- + ----- +
NOTA: Esta pergunta baseia-se em uma anterior - Obter registros com valor máximo para cada grupo de resultados SQL agrupados - para obter uma única linha superior de cada grupo e que recebeu uma ótima resposta específica do MySQL do @Bohemian:
select *
from (select * from mytable order by `Group`, Age desc, Person) x
group by `Group`
Adoraria ser capaz de construir isso, embora eu não veja como.
Respostas:
Aqui está uma maneira de fazer isso, usando
UNION ALL
(consulte SQL Fiddle with Demo ). Isso funciona com dois grupos, se você tiver mais de dois grupos, será necessário especificar ogroup
número e adicionar consultas para cada umgroup
:Há várias maneiras de fazer isso, consulte este artigo para determinar a melhor rota para sua situação:
http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/
Editar:
Isso também pode funcionar para você, pois gera um número de linha para cada registro. Usando um exemplo do link acima, ele retornará apenas os registros com um número de linha menor ou igual a 2:
Ver demonstração
fonte
SELECT
(e, de fato, às vezes as avalia fora de ordem). A chave da solução é colocar todas as atribuições de variáveis em uma única expressão; Aqui está um exemplo: stackoverflow.com/questions/38535020/… .Em outros bancos de dados, você pode fazer isso usando
ROW_NUMBER
. O MySQL não suporta,ROW_NUMBER
mas você pode usar variáveis para emular:Veja-o trabalhando on-line: sqlfiddle
Editar Acabei de notar que o bluefeet postou uma resposta muito semelhante: +1 a ele. No entanto, esta resposta tem duas pequenas vantagens:
Então, vou deixar aqui para o caso de ajudar alguém.
fonte
JOIN (SELECT @prev := NULL, @rn := 0) AS vars
. A ideia é declarar variáveis vazias, mas parece estranho para o MySql.Tente o seguinte:
DEMO
fonte
a.person
.Que tal usar a união automática:
me dá:
Fiquei fortemente inspirado pela resposta de Bill Karwin para selecionar os 10 melhores registros para cada categoria
Além disso, estou usando SQLite, mas isso deve funcionar no MySQL.
Outra coisa: acima, substituí a
group
coluna por umagroupname
coluna por conveniência.Editar :
Seguindo o comentário do OP sobre os resultados ausentes dos empates, eu aumentei a resposta do snuffin para mostrar todos os empates. Isso significa que, se os últimos forem empates, mais de 2 linhas poderão ser retornadas, conforme mostrado abaixo:
me dá:
fonte
ERROR 1242 (21000): Subquery returns more than 1 row
, presumivelmente por causa doGROUP BY
. Quando eu executar aSELECT MIN
subconsulta sozinho, ele gera três linhas:34, 39, 112
e aí aparece o segundo valor deve ser 36, não 39.A solução Snuffin parece bastante lenta de executar quando você tem muitas linhas e as soluções Mark Byers / Rick James e Bluefeet não funcionam no meu ambiente (MySQL 5.6) porque order by é aplicado após a execução de select, então aqui está uma variante das soluções Marc Byers / Rick James para corrigir esse problema (com uma seleção extra imbricada):
Eu tentei consulta semelhante em uma tabela com 5 milhões de linhas e retorna resultado em menos de 3 segundos
fonte
LIMIT 9999999
a qualquer tabela derivada com umORDER BY
. Isso pode impedir queORDER BY
seja ignorado.Veja isso:
SQL Fiddle: http://sqlfiddle.com/#!2/cdbb6/15
fonte
max(internal_version - 1)
- assim menos estresse :)Se as outras respostas não forem rápidas o suficiente Experimente este código :
Resultado:
fonte
Eu queria compartilhar isso porque passei muito tempo procurando uma maneira fácil de implementar isso em um programa java no qual estou trabalhando. Isso não dá exatamente o resultado que você está procurando, mas está próximo. A função no mysql chamada
GROUP_CONCAT()
funcionou muito bem para especificar quantos resultados retornar em cada grupo. UsarLIMIT
ou qualquer outra maneira sofisticada de tentar fazer issoCOUNT
não funcionou para mim. Portanto, se você deseja aceitar uma saída modificada, é uma ótima solução. Digamos que eu tenha uma tabela chamada 'aluno' com os IDs dos alunos, seu sexo e gpa. Vamos dizer que eu quero top 5 gpas para cada gênero. Então eu posso escrever a consulta assimObserve que o parâmetro '5' informa quantas entradas concatenar em cada linha
E a saída seria algo como
Você também pode alterar a
ORDER BY
variável e ordená-la de uma maneira diferente. Portanto, se eu tivesse a idade do aluno, poderia substituir o 'gpa desc' por 'age desc' e ele funcionará! Você também pode adicionar variáveis ao grupo por instrução para obter mais colunas na saída. Portanto, essa é apenas uma maneira que achei bastante flexível e funciona bem se você estiver bem apenas listando os resultados.fonte
No SQL Server
row_numer()
é uma função poderosa que pode obter resultados facilmente como abaixofonte
Existe uma resposta muito boa para esse problema no MySQL - Como obter as principais linhas N por cada grupo
Com base na solução no link referenciado, sua consulta seria como:
onde
n
está otop n
eyour_table
é o nome da sua tabela.Eu acho que a explicação na referência é realmente clara. Para uma referência rápida, copia e colo aqui:
fonte