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
    )