Postgres: distinto pero solo para una columna


120

Tengo una tabla en pgsql con nombres (que tiene más de 1 millón de filas), pero también tengo muchos duplicados. Selecciono 3 campos: id, name, metadata.

Quiero seleccionarlos aleatoriamente con ORDER BY RANDOM()y LIMIT 1000, así que hago varios pasos para ahorrar algo de memoria en mi script PHP.

Pero, ¿cómo puedo hacer eso para que solo me dé una lista sin duplicados en los nombres?

Por ejemplo [1,"Michael Fox","2003-03-03,34,M,4545"], se devolverá pero no [2,"Michael Fox","1989-02-23,M,5633"]. El campo de nombre es el más importante y debe ser único en la lista cada vez que hago la selección y debe ser aleatorio.

Intenté con GROUP BY name, pero luego espera que tenga una identificación y metadatos en la GROUP BYfunción también o en una función adicional, pero no quiero que se filtren de alguna manera.

¿Alguien sabe cómo obtener muchas columnas pero solo hacer una diferencia en una columna?

Respuestas:


226

Para hacer una diferenciación en solo una (on) columna (s):

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

Esto devolverá cualquiera de las filas que contienen el nombre. Si desea controlar cuál de las filas se devolverá, debe hacer un pedido:

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

Devolverá la primera fila cuando lo ordene col1.

distinct on:

SELECT DISTINCT ON (expresión [, ...]) mantiene solo la primera fila de cada conjunto de filas donde las expresiones dadas se evalúan como iguales. Las expresiones DISTINCT ON se interpretan usando las mismas reglas que para ORDER BY (ver arriba). Tenga en cuenta que la "primera fila" de cada conjunto es impredecible a menos que se utilice ORDER BY para garantizar que la fila deseada aparezca primero.

Las expresiones DISTINCT ON deben coincidir con las expresiones ORDER BY más a la izquierda. La cláusula ORDER BY normalmente contendrá expresiones adicionales que determinan la precedencia deseada de filas dentro de cada grupo DISTINCT ON.


Buen truco para ordenar. No lo incluí porque mencionaron que querían un pedido aleatorio, pero es importante mencionarlo de todos modos.
Craig Ringer

¿Es el order by namerequerido? ¿Produciría un resultado diferente con order by col1?
Elliot Chance

1
@elliot sí namees necesario. Consulte distinct onel manual.
Clodoaldo Neto

1
Ojalá el equipo de TSQL pudiera proporcionar una forma tan sensata de hacer esto.
JTW


17

¿Alguien sabe cómo obtener muchas columnas pero solo hacer una diferencia en una columna?

Quieres la DISTINCT ONcláusula .

No proporcionaste datos de muestra o una consulta completa, así que no tengo nada que mostrarte. Quieres escribir algo como:

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

Esto devolverá un conjunto de filas impredecible (pero no "aleatorio"). Si desea que sea predecible, agregue una ORDER BYrespuesta de Clodaldo. Si quieres que sea realmente aleatorio, querrás hacerlo ORDER BY random().


Solo tenga en cuenta que con esta cláusula DISTINCT ON, solo puede ORDENAR POR lo mismo + más. Entonces, si dice DISTINCT ON (nombre), debe ORDER BY name y luego cualquier otra cosa que desee. Difícilmente ideal.
Kevin Parker

Kevin, puede usar un CTE o una subconsulta en FROM y ORDER BY en la consulta externa
Craig Ringer

Sí, y observe cómo avanza la actuación ... Se buscarán todos los resultados posibles del espacio de índice. Convierte lo que podría ser una consulta de 10-20 ms con el índice correcto en una de 900 ms solo porque posgres no puede manejar un orden distinto / diferente. Ni siquiera importa cuál sea el orden de la consulta externa, utilizará el índice de la subconsulta interna para buscar coincidencias primero y luego volver a ordenar. Feliz de hacer una tarifa de consultoría para soluciones reales a nuestros problemas en dba.stackexchange.com/questions/260852/…
Kevin Parker

4
SELECT NAME,MAX(ID) as ID,MAX(METADATA) as METADATA 
from SOMETABLE
GROUP BY NAME

2
Solo una advertencia: es posible que no devuelva el valor de ID o el valor de metadatos que pertenecen "juntos"
a_horse_with_no_name

@Novum No. Significa que gato toma un valor de identificación de una de las filas de Michael y los metadatos de otra, ya que se le solicitó para los máximos de Michael.
Clodoaldo Neto

Bueno, sí, depende en gran medida de los usos de OP de datos reales, que desconozco por completo. Puede que necesite utilizar MIN o lo que sea. Acabo de demostrar cómo se pueden incluir campos que no estén en una GROUP BYcláusula.
David Jashi

Esta no es una buena solución porque se mezclarán diferentes valores de diferentes filas.
Elliot Chance
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.