Postgres: Deutlich, aber nur für eine Spalte

120

Ich habe eine Tabelle auf pgsql mit Namen (mit mehr als 1 Million Zeilen), aber ich habe auch viele Duplikate. Ich wähle drei Felder: id, name, metadata.

Ich möchte sie zufällig mit ORDER BY RANDOM()und auswählen LIMIT 1000, daher sind dies viele Schritte, um Speicherplatz in meinem PHP-Skript zu sparen.

Aber wie kann ich das tun, damit ich nur eine Liste ohne Duplikate in den Namen bekomme?

Zum Beispiel [1,"Michael Fox","2003-03-03,34,M,4545"]wird zurückgegeben, aber nicht [2,"Michael Fox","1989-02-23,M,5633"]. Das Namensfeld ist das wichtigste und muss bei jeder Auswahl in der Liste eindeutig sein. Es muss zufällig sein.

Ich habe es mit versucht GROUP BY name, aber dann erwartet es, dass ich ID und Metadaten auch in der GROUP BYoder in einer Aggragate-Funktion habe, aber ich möchte nicht, dass sie irgendwie gefiltert werden.

Weiß jemand, wie man viele Spalten abruft, aber nur eine Spalte unterscheidet?

NovumCoder
quelle

Antworten:

225

So unterscheiden Sie nur eine (oder n) Spalte (n):

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

Dies gibt alle Zeilen zurück, die den Namen enthalten. Wenn Sie steuern möchten, welche der Zeilen zurückgegeben wird, müssen Sie Folgendes bestellen:

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

Gibt die erste Zeile zurück, wenn sie von col1 bestellt wird.

distinct on::

SELECT DISTINCT ON (Ausdruck [, ...]) behält nur die erste Zeile jedes Satzes von Zeilen bei, in denen die angegebenen Ausdrücke gleich sind. Die DISTINCT ON-Ausdrücke werden nach denselben Regeln wie für ORDER BY interpretiert (siehe oben). Beachten Sie, dass die „erste Zeile“ jedes Satzes nicht vorhersehbar ist, es sei denn, ORDER BY wird verwendet, um sicherzustellen, dass die gewünschte Zeile zuerst angezeigt wird.

Die DISTINCT ON-Ausdrücke müssen mit den ORDER BY-Ausdrücken ganz links übereinstimmen. Die ORDER BY-Klausel enthält normalerweise zusätzliche Ausdrücke, die die gewünschte Priorität von Zeilen innerhalb jeder DISTINCT ON-Gruppe bestimmen.

Clodoaldo Neto
quelle
Guter Fang bei der Bestellung. Ich habe es nicht aufgenommen, weil sie erwähnt haben, dass sie eine zufällige Bestellung wünschen, aber es ist trotzdem wichtig zu erwähnen.
Craig Ringer
Ist das order by nameerforderlich? Würde es mit ein anderes Ergebnis bringen order by col1?
Elliot Chance
1
@elliot ja nameist notwendig. Überprüfen Sie distinct onim Handbuch.
Clodoaldo Neto
1
Ich wünschte, das TSQL-Team könnte einen so vernünftigen Weg bieten, dies zu tun.
JTW
Bitte fügen Sie die entsprechende postgresql Referenz hinzu
Ogaga Uzoh
17

Weiß jemand, wie man viele Spalten abruft, aber nur eine Spalte unterscheidet?

Sie wollen die DISTINCT ONKlausel .

Sie haben keine Beispieldaten oder eine vollständige Abfrage angegeben, sodass ich Ihnen nichts zeigen kann. Sie möchten etwas schreiben wie:

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

Dies gibt einen unvorhersehbaren (aber nicht "zufälligen") Satz von Zeilen zurück. Wenn Sie es vorhersehbar machen möchten, fügen Sie eine ORDER BYAntwort pro Clodaldo hinzu. Wenn Sie es wirklich zufällig machen wollen, werden Sie wollen ORDER BY random().

Craig Ringer
quelle
Beachten Sie nur, dass Sie mit dieser DISTINCT ON-Klausel nur nach dem gleichen + ORDER BESTELLEN können. Wenn Sie also DISTINCT ON (Name) sagen, müssen Sie nach Namen ordnen, was auch immer Sie wollen. Kaum ideal.
Kevin Parker
Kevin, Sie können einfach einen CTE oder eine Unterabfrage von FROM und ORDER BY in der äußeren Abfrage verwenden
Craig Ringer
Ja, und beobachten Sie die Leistung ... Die gesamten möglichen Ergebnisse aus dem Indexbereich werden durchsucht. Es stellt sich , was könnte man eine 10-20ms Abfrage mit dem rechten Index in eine 900ms sein , nur weil posgres nicht eine andere eindeutige / Bestellung von handhaben kann. Es spielt keine Rolle, wie die äußere Abfragereihenfolge lautet. Der Index aus der inneren Unterabfrage wird verwendet, um zuerst Übereinstimmungen zu finden und dann neu zu sortieren. Gerne
Kevin Parker
4
SELECT NAME,MAX(ID) as ID,MAX(METADATA) as METADATA 
from SOMETABLE
GROUP BY NAME
David Jashi
quelle
2
Nur ein Wort der Vorsicht: Das gibt möglicherweise nicht den ID-Wert oder den Metadatenwert zurück, die "zusammen" gehören
a_horse_with_no_name
@Novum Nein. Dies bedeutet, dass die Katze einen ID-Wert aus einer der Michael-Zeilen und die Metadaten aus einer anderen Zeile erhält, da nach Michaels Maxima gefragt wurde.
Clodoaldo Neto
Nun ja, es hängt stark von den realen Daten ab, die OP verwendet, von denen ich absolut nichts weiß. Möglicherweise müssen Sie MIN oder was auch immer verwenden. Nur demonstriert, wie Sie Felder einfügen können, die nicht in einer GROUP BYKlausel enthalten sind.
David Jashi
Dies ist keine gute Lösung, da unterschiedliche Werte aus unterschiedlichen Zeilen verwechselt werden.
Elliot Chance