Postgres: distinto, mas apenas para uma coluna

120

Eu tenho uma tabela no pgsql com nomes (com mais de 1 milhão de linhas), mas também tenho muitas duplicatas. Eu seleciono 3 campos: id, name, metadata.

Quero selecioná-los aleatoriamente com ORDER BY RANDOM()e LIMIT 1000, por isso, faço várias etapas para economizar memória no meu script PHP.

Mas como posso fazer isso para que apenas me dê uma lista sem duplicatas nos nomes.

Por exemplo [1,"Michael Fox","2003-03-03,34,M,4545"], será retornado, mas não [2,"Michael Fox","1989-02-23,M,5633"]. O campo de nome é o mais importante e deve ser exclusivo na lista sempre que eu faço a seleção e deve ser aleatório.

Eu tentei com GROUP BY name, mas espera que eu tenha id e metadados na GROUP BYfunção também ou em uma função agregada, mas não quero tê-los de alguma forma filtrados.

Alguém sabe como buscar muitas colunas, mas faz apenas uma distinta em uma coluna?

NovumCoder
fonte

Respostas:

225

Para fazer uma distinta em apenas uma (ou n) coluna (s):

select distinct on (name)
    name, col1, col2
from names

Isso retornará qualquer uma das linhas que contêm o nome. Se você deseja controlar qual das linhas será retornada, precisará solicitar:

select distinct on (name)
    name, col1, col2
from names
order by name, col1

Retornará a primeira linha quando solicitada por col1.

distinct on:

SELECT DISTINCT ON (expressão [, ...]) mantém apenas a primeira linha de cada conjunto de linhas em que as expressões dadas são avaliadas como iguais. As expressões DISTINCT ON são interpretadas usando as mesmas regras de ORDER BY (veja acima). Observe que a “primeira linha” de cada conjunto é imprevisível, a menos que ORDER BY seja usado para garantir que a linha desejada apareça primeiro.

As expressões DISTINCT ON devem corresponder à (s) expressão (s) ORDER BY mais à esquerda. A cláusula ORDER BY normalmente contém expressões adicionais que determinam a precedência desejada de linhas dentro de cada grupo DISTINCT ON.

Clodoaldo Neto
fonte
Boa captura de pedidos. Eu não o incluí porque eles mencionaram querer um pedido aleatório, mas é importante mencionar de qualquer maneira.
Craig Ringer
É order by namenecessário? Produziria um resultado diferente com order by col1?
Elliot Chance
1
@elliot yes nameé necessário. Verifique distinct onno manual.
Clodoaldo Neto
1
Eu gostaria que a equipe TSQL pudesse fornecer uma maneira tão sensata de fazer isso.
JTW
Por favor, adicione a referência
Ogaga Uzoh 30/11
17

Alguém sabe como buscar muitas colunas, mas faz apenas uma distinta em uma coluna?

Você quer que a DISTINCT ONcláusula .

Você não forneceu dados de amostra ou uma consulta completa, por isso não tenho nada para lhe mostrar. Você deseja escrever algo como:

SELECT DISTINCT ON (name) fields, id, name, metadata FROM the_table;

Isso retornará um conjunto de linhas imprevisível (mas não "aleatório"). Se você quiser torná-lo previsível, adicione uma ORDER BYresposta por Clodaldo. Se você quiser torná-lo verdadeiramente aleatório, você desejará ORDER BY random().

Craig Ringer
fonte
Observe que, com esta cláusula DISTINCT ON, você só pode ENCOMENDAR pela mesma coisa e mais. Portanto, se você disser DISTINCT ON (nome), deverá ORDENAR POR nome, e então o que quiser. Dificilmente ideal.
Kevin Parker
Kevin, você pode simplesmente usar um CTE ou subconsulta-de-FROM e ORDER BY na consulta externa
Craig Ringer
Sim, e observe o desempenho ... Todos os resultados possíveis do espaço de índice serão pesquisados. Transforma o que poderia ser uma consulta de 10 a 20ms com o índice correto em uma consulta de 900ms apenas porque o posgres não consegue lidar com uma distinta / ordem diferente. Nem importa qual é a ordem da consulta externa, ele usará o índice da subconsulta interna para encontrar as correspondências primeiro e depois classificá-las novamente. É um prazer
Kevin Parker
4
SELECT NAME,MAX(ID) as ID,MAX(METADATA) as METADATA 
from SOMETABLE
GROUP BY NAME
David Jashi
fonte
2
Apenas uma palavra de cautela: que pode não retornar o valor de identidade ou o valor de metadados que pertencem "juntos"
a_horse_with_no_name
@Novum Não. Isso significa que o gato recebe um valor de identificação de uma das linhas de Michael e os metadados de outra, conforme solicitado pelos máximos de Michael.
Clodoaldo Neto
Bem, sim, isso depende muito dos dados reais usados ​​pelo OP, dos quais eu sou absolutamente ignorante. Pode ser necessário usar o MIN ou o que for. Apenas demonstrado, como você pode incluir campos que não estão em uma GROUP BYcláusula.
precisa saber é o seguinte
Essa não é uma boa solução, pois valores diferentes de linhas diferentes serão confundidos.
Elliot Possibilidade