Postgres: Odrębny, ale tylko dla jednej kolumny

120

Mam tabelę na pgsql z nazwami (mającą więcej niż 1 mln wierszy), ale mam też wiele duplikatów. I wybrać 3 pola: id, name, metadata.

Chcę je wybierać losowo za pomocą ORDER BY RANDOM()i LIMIT 1000, więc robię to wiele kroków, aby zaoszczędzić trochę pamięci w moim skrypcie PHP.

Ale jak mogę to zrobić, aby uzyskać tylko listę, która nie ma duplikatów w nazwach.

Na przykład [1,"Michael Fox","2003-03-03,34,M,4545"]zostanie zwrócony, ale nie [2,"Michael Fox","1989-02-23,M,5633"]. Pole nazwy jest najważniejsze i musi być unikalne na liście za każdym razem, gdy dokonuję wyboru, i musi być losowe.

Próbowałem z GROUP BY name, ale oczekuje, że będę mieć identyfikator i metadane GROUP BYrównież lub w funkcji agregującej, ale nie chcę, aby były w jakiś sposób filtrowane.

Każdy wie, jak pobrać wiele kolumn, ale tylko wyróżnić jedną kolumnę?

NovumCoder
źródło

Odpowiedzi:

226

Aby wyróżnić tylko jedną (lub n) kolumnę (kolumny):

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

Spowoduje to zwrócenie dowolnego wiersza zawierającego nazwę. Jeśli chcesz kontrolować, które wiersze zostaną zwrócone, musisz zamówić:

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

Zwróci pierwszy wiersz, gdy zostanie uporządkowany według col1.

distinct on:

SELECT DISTINCT ON (wyrażenie [, ...]) zachowuje tylko pierwszy wiersz każdego zestawu wierszy, w przypadku których dane wyrażenia są równe. Wyrażenia DISTINCT ON są interpretowane przy użyciu tych samych reguł, co ORDER BY (patrz wyżej). Zwróć uwagę, że „pierwszy wiersz” każdego zestawu jest nieprzewidywalny, chyba że użyto polecenia ORDER BY, aby upewnić się, że żądany wiersz pojawi się jako pierwszy.

Wyrażenia DISTINCT ON muszą być zgodne z wyrażeniami ORDER BY znajdującymi się najbardziej po lewej stronie. Klauzula ORDER BY zwykle będzie zawierała dodatkowe wyrażenia, które określają pożądany priorytet wierszy w każdej grupie DISTINCT ON.

Clodoaldo Neto
źródło
Dobry chwyt przy zamawianiu. Nie włączyłem tego, ponieważ wspomnieli, że chcą losowo zamówić, ale i tak ważne jest, aby o tym wspomnieć.
Craig Ringer
Czy jest to order by namewymagane? Czy przyniosłoby to inny wynik order by col1?
Elliot Chance
1
@elliot yes namejest konieczne. Sprawdź distinct onw instrukcji.
Clodoaldo Neto
1
Chciałbym, aby zespół TSQL zapewnił taki rozsądny sposób zrobienia tego.
JTW
Dodaj odpowiednie odniesienie do
Ogaga Uzoh
17

Każdy wie, jak pobrać wiele kolumn, ale tylko wyróżnić jedną kolumnę?

Chcesz się DISTINCT ONklauzulę .

Nie podałeś przykładowych danych ani pełnego zapytania, więc nie mam Ci nic do pokazania. Chcesz napisać coś takiego:

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

Spowoduje to zwrócenie nieprzewidywalnego (ale nie „losowego”) zestawu wierszy. Jeśli chcesz, aby było przewidywalne, dodaj odpowiedź ORDER BYwedług Clodaldo. Jeśli chcesz, aby było to naprawdę losowe, będziesz chciał ORDER BY random().

Craig Ringer
źródło
Zwróć uwagę, że z tą klauzulą ​​DISTINCT ON możesz ZAMAWIAĆ tylko przez to samo + więcej. Więc jeśli powiesz DISTINCT ON (name), musisz ZAMÓWIĆ WEDŁUG nazwy, a następnie cokolwiek chcesz. Mało idealna.
Kevin Parker
Kevin, możesz po prostu użyć CTE lub podzapytania z FROM i ORDER BY w zewnętrznym zapytaniu
Craig Ringer
Tak, i patrz, jak idzie ... Przeszukane zostaną wszystkie możliwe wyniki z przestrzeni indeksu. Zamienia to, co mogłoby być zapytaniem 10-20 ms z właściwym indeksem w 900 ms tylko dlatego, że posgres nie może obsłużyć innego odrębnego / zamówienia według. Nie ma nawet znaczenia, jaka jest zewnętrzna kolejność zapytań, użyje indeksu z wewnętrznego podzapytania, aby najpierw znaleźć dopasowania, a następnie ponownie posortować. Chętnie udzielę
Kevin Parker
4
SELECT NAME,MAX(ID) as ID,MAX(METADATA) as METADATA 
from SOMETABLE
GROUP BY NAME
David Jashi
źródło
2
Tylko słowo ostrzeżenia: to może nie zwrócić wartości identyfikatora lub wartości metadanych, które należą do „razem”
a_horse_with_no_name
@Novum Nie. Oznacza to, że cat pobiera wartość identyfikatora z jednego z wierszy Michaela, a metadane z innego, ponieważ został poproszony o podanie maksymalnych wartości Michaela.
Clodoaldo Neto
Cóż, tak, w dużej mierze zależy to od rzeczywistych zastosowań OP danych, których jestem absolutnie nieświadomy. Może być konieczne użycie MIN lub czegokolwiek. Właśnie pokazałem, jak można uwzględnić pola, których nie ma w GROUP BYklauzuli.
David Jashi
To nie jest dobre rozwiązanie, ponieważ różne wartości z różnych wierszy zostaną pomieszane.
Elliot Chance