【问题标题】:Select last record of each month for each ID为每个 ID 选择每个月的最后一条记录
【发布时间】:2021-01-23 07:12:15
【问题描述】:

我正在尝试为每个 ID 提取每个月的最后一条记录。

下面是我请求的表格:

myTable
ID  date         data
1   2020-08-27   a
1   2020-08-28   b
1   2020-09-30   c
2   2020-08-29   d
2   2020-09-30   e

因此,我想得到以下信息:

output
ID  date         data
1   2020-08-28   b
1   2020-09-30   c
2   2020-08-29   d
2   2020-09-30   e

这里的“复杂性”是每个ID每个月的最后一条记录可能不一样。

到目前为止,我只能通过以下请求在数据库中获取每个月最后一个日期的所有可用记录:

SELECT ID, date, data
from myTable
and date in (SELECT max(date) FROM myTable GROUP BY strftime('%Y-%m', date))

这给了我这个

wrong output
ID  date         data
1   2020-09-30   c
2   2020-08-29   d
2   2020-09-30   e

【问题讨论】:

    标签: sql sqlite subquery greatest-n-per-group window-functions


    【解决方案1】:

    您可以使用相关子查询进行过滤:

    select t.*
    from mytable t
    and date = (
        select max(t1.date) 
        from mytable t1 
        where strftime('%Y-%m', t1.date) = strftime('%Y-%m', t.date) and t1.id = t.id
    )
    

    另一种方法使用窗口函数:

    select *
    from (
        select t.*,
            rank() over(partition by id, strftime('%Y-%m', date) order by date desc) rn
        from mytable t
    ) t
    where rn = 1
    

    【讨论】:

    • 非常感谢您的回答。使用 windows 选项的第二个选项效果很好。第一个虽然没有,但乍一看更吸引人,因为我不知道 windows 功能。
    • @GMB 您的两个查询都不起作用:strftime('%y-%m', date) 针对 SQLite 中的任何有效日期返回 nulldb-fiddle.com/f/q5b2YyqvFz1E1ZfLK5vKT7/0 此外,您的第二个查询是在我的回答之后发布的,因为最初您只发布了第一个查询,您稍后添加了第二个查询,尽管编辑时间戳不会在问题的初始发布后这样的排序时间内保存编辑。
    • @forpas:好的,我将%y 固定为%Y(我认为这是一个错字...),谢谢。这就是为什么你的答案应该被接受的一个很好的理由(而不是讨论发布时间戳)。
    【解决方案2】:

    使用 ROW_NUMBER() 窗口函数:

    SELECT ID, date, data
    FROM (
      SELECT *,
        ROW_NUMBER() OVER (PARTITION BY ID, strftime('%Y%m', date) ORDER BY date DESC) rn
      FROM myTable 
    )
    WHERE rn = 1
    

    【讨论】:

    • 非常感谢,这太棒了。我不知道windows功能。
    猜你喜欢
    • 1970-01-01
    • 2018-06-28
    • 2020-10-01
    • 2014-11-19
    • 2021-11-04
    • 1970-01-01
    • 1970-01-01
    • 2015-08-21
    • 1970-01-01
    相关资源
    最近更新 更多