Sql 在postgres中以性能方式获取最大值和相应列
我有一个奇怪的情况 假设我需要知道以下信息:对于给定的面包店,我需要知道关于他们最甜蛋糕的所有信息,以及关于他们最新蛋糕的所有信息。所以我们的数据看起来像这样Sql 在postgres中以性能方式获取最大值和相应列,sql,postgresql,query-optimization,greatest-n-per-group,Sql,Postgresql,Query Optimization,Greatest N Per Group,我有一个奇怪的情况 假设我需要知道以下信息:对于给定的面包店,我需要知道关于他们最甜蛋糕的所有信息,以及关于他们最新蛋糕的所有信息。所以我们的数据看起来像这样 ------------------------------------- bakery | name | created_timestamp | sweetness_score marios | blueberry | 100 | 4 marios | razberry | 115
-------------------------------------
bakery | name | created_timestamp | sweetness_score
marios | blueberry | 100 | 4
marios | razberry | 115 | 2
luigis | angels | 120 | 5
luigis | devils | 155 | 1
-------------------------------------
最终的数据输出应该如下所示
{
mario:
sweetestCake:{
name: blueberry,
sweetness_score: 4,
created_timestamp: 100
},
mostRecentCake: {
name: razberry,
sweetness_score: 2,
created_timestamp: 115
}
},
luigi: // same concept but for luigi's cakes
我正在使用秩窗口函数并仅选择秩=1的位置。例如,最甜的蛋糕可以用
SELECT * FROM (
SELECT RANK () OVER (PARTITION BY (BAKERY) ORDER BY sweetness_score DESC)
AS rank_of_sweetness
) as sweetness
WHERE rank_of_sweetness = 1;
但这不是很有效
我用MAX
和窗口函数LAST\u VALUE
处理了很多不同的想法,它们可以检索正确的甜度得分
,但是获取我需要的其他列是一件痛苦的事
我如何才能以更有效的方式完成这项工作?或者,不管怎样,RANK将是我的最佳选择吗?解决方案是很好的,并且是解决问题的一种规范方法:
select *
from (
select t.*,
rank() over(partition by bakery order by sweetness_score desc) rn1,
rank() over(partition by bakery order by created_timestamp desc) rn2
from mytable t
)
where 1 in (rn1, rn2)
在Postgres中,您还可以使用distinct on()
。这是一个方便的扩展,可能会更优化。可以使用union
同时获得这两个结果(如果一行既有最大的甜度又有最新的时间戳,则可以故意不使用union all
):
我很想知道新的fetch
子句(在Postgres 13中提供)在这里是否有用。一个好处是,您可以使用它同时对两个匹配项进行过滤(这是distinct on
无法做到的):
如果这些都没有帮助,那么另一种方法是使用相关子查询解决方案:
select *
from mytable t
where
t.sweetness_score = (
select max(t1.sweetness_score)
from mytable t1
where t1.bakery = t.bakery
)
or t.created_timestamp = (
select max(t1.created_timestamp)
from mytable t1
where t1.bakery = t.bakery
)
对于这个查询,您需要
(bakery,sweetness\u score)
和(bakery,created\u timestamp)
我对这个答案投了更高的票,我认为没问题。他们真的应该要求你在允许你投否决票之前有一个更好的答案。lol。与工会的区别似乎对我来说不会太明显,但这可能值得一试!
select *
from mytable
order by least(
rank() over(partition by bakery order by sweetness_score desc),
rank() over(partition by bakery order by created_timestamp desc)
)
fetch first row with ties
select *
from mytable t
where
t.sweetness_score = (
select max(t1.sweetness_score)
from mytable t1
where t1.bakery = t.bakery
)
or t.created_timestamp = (
select max(t1.created_timestamp)
from mytable t1
where t1.bakery = t.bakery
)