2016-09-26 1 views
0

J'ai une base de données parallèle à la base de données 'widget' ci-dessous.Requête GROUP BY PostgreSQL où j'ai besoin d'une colonne qui ne figure pas dans la clause GROUP BY

widget_id | vendor_id | price 
------------------------------ 
    1  | 101 | 10.00 
    2  | 101 | 9.00 
    3  | 102 | 6.00 
    4  | 102 | 7.00 

Je veux trouver le widget moins cher par le vendeur, donc quelque chose comme la sortie ci-dessous:

widget_id | vendor_id | price 
------------------------------ 
    1  | 101 | 10.00 
    3  | 102 | 6.00 

MySQL ou SQLite, je pourrais interroger

SELECT widget_id, vendor_id, min(price) AS price FROM widgets GROUP BY(vendor_id) 

Cependant, il semble que cela est contraire à la spécification SQL. Dans PostgreSQL, je ne peux pas exécuter la requête ci-dessus. Le message d'erreur est "widget_id doit apparaître dans la clause GROUP BY ou être utilisé dans une fonction d'agrégat". Je peux un peu voir le point de PostgreSQL, mais il semble tout à fait raisonnable de vouloir le widget_id du widget qui a le prix minimum.

Qu'est-ce que je fais mal?

+1

Votre code dans MySQL et SQLite est incorrect. Il n'est pas garanti de renvoyer le résultat correct. –

Répondre

1

Vous pouvez utiliser DISTINCT ON:

SELECT DISTINCT ON (vendor_id) * 
FROM widget 
ORDER BY vendor_id, price; 

Vous pouvez également utiliser la fonction de fenêtre row_number dans une sous-requête:

SELECT widget_id, vendor_id, price 
FROM (
    SELECT *, row_number() OVER (PARTITION BY vendor_id ORDER BY price) AS rn 
    FROM widget 
) t 
WHERE rn=1; 

Finaly, vous pouvez aussi le faire avec un LATERAL rejoindre:

SELECT t2.* 
FROM 
    (SELECT DISTINCT vendor_id FROM widget) t1, 
    LATERAL (SELECT * FROM widget WHERE vendor_id=t1.vendor_id ORDER BY price LIMIT 1) t2