我的数据格式与此类似
+--------+------------+-------+
| type | variety | price |
+--------+------------+-------+
| apple | gala | 2.79 |
| apple | fuji | 0.24 |
| apple | limbertwig | 2.87 |
| orange | valencia | 3.59 |
| orange | navel | 9.36 |
| pear | bradford | 6.05 |
| pear | bartlett | 2.14 |
| cherry | bing | 2.55 |
| cherry | chelan | 6.33 |
+--------+------------+-------+
而且我希望每种类型都能获得最高价格和最低价格的行,也应该从价格最高的行中获取品种
+--------+------------+-------+-------+
| type | variety | min | max |
+--------+------------+-------+-------+
| apple | limbertwig | 0.24 | 2.87 |
| orange | navel | 9.36 | 3.59 |
| pear | bradford | 6.05 | 2.14 |
| cherry | chelan | 6.33 | 2.55 |
+--------+------------+-------+-------+
使用Postgres实现这一目标的最佳方法是什么?
我找到了这个网站:How to select the first/least/max row per group in SQL,但这不是我需要的。
答案 0 :(得分:2)
找到价格最低的水果:
select distinct on (type) type, variety, price
from fruits
order by 1, 3;
type | variety | price
--------+----------+-------
apple | fuji | 0.24
cherry | bing | 2.55
orange | valencia | 3.59
pear | bartlett | 2.14
(4 rows)
找到价格最高的水果:
select distinct on (type) type, variety, price
from fruits
order by 1, 3 desc;
type | variety | price
--------+------------+-------
apple | limbertwig | 2.87
cherry | chelan | 6.33
orange | navel | 9.36
pear | bradford | 6.05
(4 rows)
合并两个查询:
select
f1.type,
f1.variety min_variety, f1.price min_price,
f2.variety max_variety, f2.price max_price
from (
select distinct on (type) type, variety, price
from fruits
order by 1, 3) f1
join (
select distinct on (type) type, variety, price
from fruits
order by 1, 3 desc) f2
on f1.type = f2.type
type | min_variety | min_price | max_variety | max_price
--------+-------------+-----------+-------------+-----------
apple | fuji | 0.24 | limbertwig | 2.87
cherry | bing | 2.55 | chelan | 6.33
orange | valencia | 3.59 | navel | 9.36
pear | bartlett | 2.14 | bradford | 6.05
(4 rows)
替代那些不能使用具有强大功能的Postgres的人:
select
f1.type,
f1.variety min_variety, f1.price min_price,
f2.variety max_variety, f2.price max_price
from (
select f.type, f.variety, f.price
from (
select type, min(price) minprice
from fruits group by type
) x
join fruits f on f.type = x.type and f.price = x.minprice
) f1
join (
select f.type, f.variety, f.price
from (
select type, max(price) maxprice
from fruits group by type
) x
join fruits f on f.type = x.type and f.price = x.maxprice
) f2
on f1.type = f2.type
order by 1;
答案 1 :(得分:2)
您的结果表示例的三个行的最小值和最大值都是错误的;)
另一种方法 - 与上面的答案1类似,是CTE:
WITH mini AS (
select type
, MIN(price) as minprice
FROM fruits
GROUP BY type
), maxi AS (
select type
, MAX(price) as maxprice
FROM fruits
GROUP BY type
)
SELECT fruits.type
, fruits.variety as max_variety
, mini.minprice
, maxi.maxprice
FROM fruits
JOIN mini ON mini.type = fruits.type
JOIN maxi ON maxi.type = fruits.type AND maxi.maxprice = fruits.price
WHERE fruits.price = maxi.maxprice
AND fruits.type = maxi.type
ORDER BY fruits.type
答案 2 :(得分:1)
这种性质的问题(获得表中每个组的最大,最小,平均,第一,最后......)最好用所谓的window function来解决。使用窗口函数,您可以将数据PARTITION
分组(在"type"
列上),然后在分区上应用一些window function或aggregate function。该功能适用于分区中所谓的帧;默认情况下,框架从分区中的第一行运行到当前行,但是可以像在此答案中一样更改此默认值。
SELECT DISTINCT "type", last_value(variety) OVER w AS variety
first_value(price) OVER w AS min, last_value(price) OVER w AS max
FROM my_table
WINDOW w AS (PARTITION BY "type" ORDER BY price
RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
ORDER BY 1;
请注意,窗口函数或聚合函数会将列添加到输出中,就像在常规情况下一样。在上面的答案中,DISTINCT
子句用于为每个“类型”的水果只获得一行。如果没有该子句,您将获得每个输入行的输出行,并为每个“类型”的水果重复数据。
使用窗口函数也意味着您只对表执行一次扫描,而不使用任何临时表(与子选择或CTE一样)或连接。在较大的表上,这应该会在性能上产生很大的差异。此外,它还可以根据其他要求进行更好的扩展(例如将平均价格添加到输出中)。
答案 3 :(得分:0)
use ErrorResponseWrapper::ErrorResponse;