I have a database that parallels the 'widget' database below.
widget_id | vendor_id | price
------------------------------
1 | 101 | 10.00
2 | 101 | 9.00
3 | 102 | 6.00
4 | 102 | 7.00
I want to find the cheapest widget by vendor, so something like the below output:
widget_id | vendor_id | price
------------------------------
1 | 101 | 10.00
3 | 102 | 6.00
In MySQL or SQLite, I could query
SELECT widget_id, vendor_id, min( price ) AS price FROM widgets GROUP BY( vendor_id )
However, it seems that this is contrary to the SQL spec. In PostgreSQL, I'm unable to run the above query. The error message is "widget_id must appear in the GROUP BY clause or be used in an aggregate function". I can kind of see PostgreSQL's point, but it seems like a perfectly reasonable thing to want the widget_id of the widget that has the minimum price.
What am I doing wrong?
You can use DISTINCT ON
:
SELECT DISTINCT ON (vendor_id) *
FROM widget
ORDER BY vendor_id, price;
You can also use the row_number
window function in a subquery:
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, you can also do it with a LATERAL
join:
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With