【问题标题】:Get latest record based on two fields [closed]根据两个字段获取最新记录[关闭]
【发布时间】:2021-10-02 18:18:32
【问题描述】:

我有一个包含以下字段的表格:

user_id         year      month     amount    type
--------------------------------------------------
5               2018      1         100       Foo
6               2017      12        100       Bar
6               2018      11        100       Foo
6               2018      12        100       Bar
7               2018      12        100       Foo
7               2019      12        100       Bar
8               2019      12        100       Foo

我想做三件事:

  1. 获取特定用户的每个用户 ID 的最新记录(1 条记录,最新年份和月份字段),

类似:

select *
from myTable
where user_id in (6,7) and <is latest year / month>

应该返回

user_id         year      month     amount     type
---------------------------------------------------
6               2018      12        100        Bar
7               2019      12        100        Foo
  1. 计算上述查询的总数,例如:
    select SUM(amount) as myTotal, avg(amount) as myAverage, 
    (count # of foos in result) as numberOfFoos,
    (count # of bars in result) as numberOfBars
    from myTable
    where user_id in (6,7) and <is latest year / month>

将返回一行包含自定义字段:

myTotal     myAverage     numberOfFoos      numberOfBars
--------------------------------------------------------
300         100           2                 1
  1. 与上面的查询相同,但每个月的一段时间,例如。在过去的 3-5 年中,最好是尽可能减少调用次数,而不是手动循环 36 个月以上并单独调用。
    year     month    myTotal     myAverage     numberOfFoos      numberOfBars
    --------------------------------------------------------------------------
    2018     1        300         100           2                 1
    2018     2        300         100           2                 1
    2018     3        300         100           2                 1
    ...
    2020     12       300         100           2                 1

【问题讨论】:

  • 到目前为止您尝试了哪些方法,有什么问题?

标签: sql postgresql greatest-n-per-group


【解决方案1】:

第一个问题可以使用row_number函数解决:

with d as (
  select 
    users.*, 
    row_number() over (partition by user_id  order by year desc, month desc ) rn 
  from  users 
  where  user_id in (5, 6)
) 
select * from d
where  rn = 1;

PostgreSQL fiddle here

第二个问题可以用同样的方法解决:

with d as (
  select 
    users.*, 
    row_number() over (partition by user_id  order by year desc, month desc) rn 
  from  users 
  where  user_id in (6, 7)
) 
select 
    sum(amount), avg(amount), 
    count(*) filter (where type = 'Foo') count_foo, 
    count(*) filter (where type = 'Bar') count_bar
from d
where  rn = 1;

Test solution here

【讨论】:

  • 谢谢,这完成了我需要的大部分工作,还有另一个用例我不知道该怎么做,但我会在其他人抱怨之前创建一个单独的问题。
【解决方案2】:
select year, month, sum(amount), avg(amount),
       sum(case when type = 'Foo' then 1 else 0 end) as num_foos,
       sum(case when type = 'Bar' then 1 else 0 end) as num_bars
from (select u.*, 
             row_number() over (partition by user_id  order by year desc, month desc ) as seqnum 
      from users 
      where user_id in (5, 6)
     ) u
where seqnum = 1
group by year, month;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-21
    • 2019-07-02
    • 2021-06-30
    • 1970-01-01
    • 1970-01-01
    • 2023-01-24
    • 2021-01-24
    相关资源
    最近更新 更多