Como selecionar distinto para uma coluna e qualquer outro em outra coluna?

29

Preciso consultar um banco de dados SQL para encontrar todos os valores distintos de uma coluna e preciso de um valor arbitrário de outra coluna. Por exemplo, considere a seguinte tabela com duas colunas, chave e valor:

key     value
===     =====
one     test
one     another
one     value
two     goes
two     here
two     also
three   example

Desejo recuperar uma linha de amostra, escolhida arbitrariamente, de cada chave distinta, talvez recebendo essas três linhas:

key     value
===     =====
one     test
two     goes
three   example

Como posso formular essa consulta no SQL?

WilliamKF
fonte
2
Quais DBMS (Oracle, SQL-Server, DB2, MySQL, Postgres)?
usar o seguinte código
11
É um sistema proprietário.
precisa saber é o seguinte

Respostas:

33

A consulta mais fácil de escrever é para o MySQL (com configurações ANSI não estritas). Ele usa a construção não padrão:

SELECT key, value
FROM tableX
GROUP BY key ;

Na versão recente (5.7 e 8.0+), nas quais as configurações estritas ONLY_FULL_GROUP_BYsão o padrão, é possível usar a ANY_VALUE()função adicionada em 5.7:

SELECT key, ANY_VALUE(value) AS value
FROM tableX
GROUP BY key ;

Para outros DBMSs, que possuem funções de janela (como Postgres, SQL-Server, Oracle, DB2), você pode usá-los assim. A vantagem é que você também pode selecionar outras colunas no resultado (além de keye value):

SELECT key, value
FROM tableX
    ( SELECT key, value,
             ROW_NUMBER() OVER (PARTITION BY key 
                                ORDER BY whatever)     --- ORDER BY NULL
               AS rn                                   --- for example
      FROM tableX
    ) tmp 
WHERE rn = 1 ;

Para versões anteriores do acima e para qualquer outro DBMS, uma maneira geral que funciona em quase todos os lugares. Uma desvantagem é que você não pode selecionar outras colunas com essa abordagem. Outra é que funções agregadas como MIN()e MAX()não funcionam com alguns tipos de dados em alguns DBMSs (como bit, texto, blobs):

SELECT key, MIN(value) AS value
FROM tableX
GROUP BY key ;

O PostgreSQL possui um DISTINCT ONoperador especial não padrão que também pode ser usado. O opcional ORDER BYé para selecionar qual linha de cada grupo deve ser selecionada:

SELECT DISTINCT ON (key) key, value
FROM tableX
-- ORDER BY key, <some_other_expressions> ;
ypercubeᵀᴹ
fonte
2
@WilliamKF Se por "escolhido arbitrariamente" você quer dizer "escolhido aleatoriamente", basta substituir a ORDER BY whateverconsulta no ypercube por uma chamada para uma função para randomizar os resultados.
Leigh Riffel
11
@LeighRiffel Não precisa ser aleatório, qualquer escolha, tão simples quanto a primeira encontrada funciona bem.
WilliamKF #
3

Para MS-SQl Server:

;with FinalDataset as
(
    select *,
        row_number() over(partition by key order by value) as rownum
    from YourOriginalTable
)
select
   key,
   value
from FinalDataset 
where rownum = 1

Da mesma forma, você poderia ter rownum = 2 para o seu segundo conjunto de resultados

JP Chauhan
fonte
2

Semelhante à resposta aceita, mas em vez de min () ou max () você pode usar array_agg ()

SELECT key, (array_agg(value))[1] AS value
FROM tableX
GROUP BY key ;

Opcionalmente, você pode solicitar valores dentro da matriz para selecionar o maior ou o menor deles:

SELECT key, (array_agg(value) ORDER BY value DESC)[1] AS value
FROM tableX
GROUP BY key ;

(verificado no PostgreSQL)

alexkovelsky
fonte