Postgres: distinto ma solo per una colonna


120

Ho una tabella su pgsql con nomi (con più di 1 milione di righe), ma ho anche molti duplicati. Seleziono 3 campi: id, name, metadata.

Voglio selezionarli casualmente con ORDER BY RANDOM()e LIMIT 1000, quindi faccio molti passaggi per salvare un po 'di memoria nel mio script PHP.

Ma come posso farlo in modo che mi dia solo un elenco che non ha duplicati nei nomi.

Ad esempio [1,"Michael Fox","2003-03-03,34,M,4545"]verrà restituito ma non [2,"Michael Fox","1989-02-23,M,5633"]. Il campo del nome è il più importante e deve essere unico nell'elenco ogni volta che effettuo la selezione e deve essere casuale.

Ho provato con GROUP BY name, ma poi si aspetta che io abbia id e metadati anche nella GROUP BYfunzione o in una funzione aggragate, ma non voglio che siano filtrati in qualche modo.

Qualcuno sa come recuperare molte colonne ma solo una distinta su una colonna?

Risposte:


226

Per eseguire una distinzione su una sola (o n) colonna (e):

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

Ciò restituirà qualsiasi riga contenente il nome. Se vuoi controllare quale delle righe verrà restituita devi ordinare:

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

Restituirà la prima riga se ordinata da col1.

distinct on:

SELECT DISTINCT ON (espressione [, ...]) mantiene solo la prima riga di ogni insieme di righe in cui le espressioni date restituiscono uguale. Le espressioni DISTINCT ON vengono interpretate utilizzando le stesse regole di ORDER BY (vedi sopra). Si noti che la "prima riga" di ogni set è imprevedibile a meno che non venga utilizzato ORDER BY per garantire che la riga desiderata venga visualizzata per prima.

Le espressioni DISTINCT ON devono corrispondere alle espressioni ORDER BY più a sinistra. La clausola ORDER BY normalmente conterrà espressioni aggiuntive che determinano la precedenza desiderata delle righe all'interno di ogni gruppo DISTINCT ON.


Buona presa sull'ordinazione. Non l'ho incluso perché hanno menzionato la necessità di un ordine casuale, ma è importante menzionarlo comunque.
Craig Ringer

È order by namerichiesto? Produrrebbe un risultato diverso con order by col1?
Elliot Chance

1
@elliot sì nameè necessario. Controlla distinct onil manuale.
Clodoaldo Neto

1
Vorrei che il team TSQL potesse fornire un modo così ragionevole per farlo.
JTW

Si prega di aggiungere il riferimento
Ogaga Uzoh

17

Qualcuno sa come recuperare molte colonne ma solo una distinta su una colonna?

Vuoi la DISTINCT ONclausola .

Non hai fornito dati di esempio o una query completa, quindi non ho nulla da mostrarti. Vuoi scrivere qualcosa come:

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

Ciò restituirà un insieme di righe imprevedibile (ma non "casuale"). Se vuoi renderlo prevedibile aggiungi una ORDER BYrisposta per Clodaldo. Se vuoi renderlo veramente casuale, ti consigliamo di farlo ORDER BY random().


Nota solo con questa clausola DISTINCT ON, puoi solo ORDER BY la stessa cosa + altro. Quindi, se dici DISTINTO SU (nome) devi ORDINARE PER nome e qualsiasi altra cosa desideri. Difficilmente l'ideale.
Kevin Parker

Kevin, puoi semplicemente utilizzare un CTE o una sottoquery-in-FROM e ORDER BY nella query esterna
Craig Ringer

Sì, e guarda lo spettacolo andare ... Verranno cercati tutti i possibili risultati dallo spazio dell'indice. Trasforma quella che potrebbe essere una query da 10-20 ms con l'indice corretto in una da 900 ms solo perché posgres non può gestire un distinto / ordine diverso da. Non importa nemmeno quale sia l'ordine della query esterna, utilizzerà l'indice della sottoquery interna per trovare prima le corrispondenze, quindi riordinarle. Felice di pagare una commissione per la consulenza per soluzioni reali ai nostri problemi su 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 parola di cautela: potrebbe non restituire il valore ID o il valore dei metadati che appartengono "insieme"
a_horse_with_no_name

@ Novum No. Significa che il gatto prende un valore id da una delle righe di Michael e i metadati da un'altra come è stato chiesto per i massimi di Michael.
Clodoaldo Neto

Ebbene sì, dipende molto dai dati reali utilizzati dall'OP, di cui sono assolutamente ignorante. Potrebbe essere necessario utilizzare MIN o altro. Appena dimostrato, come puoi includere campi non in una GROUP BYclausola.
David Jashi

Questa non è una buona soluzione perché valori diversi di righe diverse verranno confusi.
Elliot Chance
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.