2009-07-28 9 views
3

Ich habe Probleme mit dem Erstellen einer SQL-Abfrage mit Aggregaten mit PostgreSQL. Betrachten Sie die folgenden Tabellen:Erhalten Primärschlüssel aggregiert, gruppieren nach SQL-Abfrage mit PostgreSQL

CREATE TABLE thing (
    id INT NOT NULL PRIMARY KEY, 
    price NUMERIC(10,2) NOT NULL, 
    description VARCHAR(255) NOT NULL, 
    url VARCHAR(255) NOT NULL, 
    location_id INT NOT NULL REFERENCES location(id) 
) 

CREATE TABLE location (
    id INT NOT NULL PRIMARY KEY, 
    type INT NOT NULL, 
    name VARCHAR(255) NOT NULL 
) 

Nun würde Ich mag alle Aufzeichnungen, die Sache für jeden Standort erhalten mit location.type = xxx, der den niedrigsten Preis haben.

Etwas wie:

SELECT min(price) FROM thing 
INNER JOIN location ON (thing.location_id = location.id) 
WHERE type = xxx 
GROUP BY location_id 

Das bin ich den niedrigsten Preis für jeden Standort mit Typ xxx auflistet, aber wie kann ich die Zeilen (oder deren Primärschlüssel) dieser Spalten aus der Tabelle Ding?

Antwort

5

verwendet PostgreSQL Erweiterung:

SELECT DISTINCT ON (location.id) thing.* 
FROM location 
JOIN thing 
ON  thing.location_id = location_id 
WHERE type = 1 
ORDER BY 
     location.id ASC, price ASC 

Diese für jeden location.id nur die erste Zeile ausgewählt wird.

Da Ihre Zeilen nach location.id und dann nach price sortiert sind, ist dies die Zeile mit dem minimalen Preis.

In neuen PostgreSQL 8.4, können Sie auch Fensterfunktionen verwenden:

SELECT * 
FROM (
     SELECT thing.*, ROW_NUMBER() OVER (PARTITION BY location_id ORDER BY price) AS rn 
     FROM location 
     JOIN thing 
     ON  thing.location_id = location_id 
     WHERE type = 1 
     ) q 
WHERE rn = 1 
+0

perfekt, das ist genau das, was ich suchte. – Haes

0

Vielleicht eine Abfrage Unter verwenden

SELECT t.id,t.description,t.price FROM 
    (SELECT location_id, min(price) FROM thing 
     INNER JOIN location ON (thing.location_id = location.id) 
     WHERE type = xxx 
     GROUP BY location_id 
    ) AS lowest 
    INNER JOIN thing AS t 
    ON t. location_id = lowest.location_id; 
0

ich eine SQL Server Typ bin, aber die folgenden sollte SQL-92 sein konform und sollte funktionieren:

Beachten Sie auch, dass ich keine Tabelle eingerichtet habe, um mit zu testen, also t hier könnte ein Tippfehler oder zwei drin sein.

Während es funktioniert, sieht es sicher peinlich aus. Wenn Postgres etwas wie die Ranking-Funktionen von SQL hat, würden sie es ein bisschen einfacher machen.

+0

Das ist auch, was ich ursprünglich erfunden habe. Das Problem mit dieser Abfrage ist, dass es mehrere Spalten für einen Standort zurückgibt, wenn der niedrigste Preis nicht eindeutig ist. – Haes

+0

Basierend auf der Beschreibung, dachte ich, das war, was Sie gesucht haben. Wenn es doppelte Dinge auf Basis des Mindestpreises gibt, welche würden Sie auswählen? (Rhetorische Frage, da Sie bereits eine Antwort haben - row_number() ist eine sehr nützliche Erweiterung.) –

3

Diese Abfrage

select thing.id,thing.description,thing.url,low.location_id,low.minimum from 
(select thing.location_id,min(price) as minimum from thing 
join location on thing.location_id=location.id 
    where location.type = 13 group by location_id) as low 
    inner join thing on thing.location_id = low.location_id 
Verwandte Themen