开发者社区> 问答> 正文

在“截至日期”的情况下有效获取最新数据

我有一些可以这样表示的数据:

CREATE TABLE #foo (
    id INT
  , year INT
  , value INT
  , date Date
)

INSERT INTO #foo (id, year, value, date)
VALUES (1, 1, 1, '2001-01-01')
     , (1, 2, 2, '2002-01-01')
     , (1, 2, 3, '2002-02-01')
     , (1, 2, 2, '2003-03-01') -- a year later!
     , (1, 3, 2, '2003-01-01')
     , (1, 3, 2, '2003-03-01')

基本上,我具有通过ID标识的一些公司的财务数据(在这种情况下,仅显示单个公司)。这些数据来自公司不时进行的披露,我拥有财务数据相关的年份以及相关财务报告的日期。

请注意,给定年份我可能有多个报告。这是因为公司可能会注意到他们先前报告的内容存在错误,并提交了“重述”以纠正这些错误。在某些情况下,即使在提交了下一个期间的结果之后,也可能要经过很长时间才能进行这些更正(例如,在这种情况下,第二年的最新报告在第三年的第一份报告之后)。

现在,我想确定过去任何给定日期知道的数据。显然,这涉及过滤在该日期之后给出的所有内容,而且还丢弃所有自此之后已得到纠正的“过时”报告(通过在“截止日期”之前重述)。

我所做的最好的事情是:(*我发誓仅用于此问题)

SELECT id, year, value, date
FROM (
    SELECT *
         , ROW_NUMBER() OVER (PARTITION BY id, year
                              ORDER BY date DESC) AS recency
    FROM (
        SELECT *
        FROM #foo
        WHERE date <= '2002-02-01'
        ) x
) y
WHERE recency = 1

-- | id | year | value |    date    |
-- |----|------|-------|------------|
-- |  1 |    1 |     1 | 2001-01-01 |
-- |  1 |    2 |     3 | 2002-02-01 |

首先,丢弃我截至日期(2002-02-01)之前的所有内容,然后使用每对(id,year)对中的行数来标识最新的报告。

这很好用,但是必须使用三个查询(一个加两个子查询)来完成这项工作很笨拙。这是正确的还是我不知道有什么技巧可以更优雅地做到这一点?

展开
收起
祖安文状元 2020-01-04 15:30:08 530 0
1 条回答
写回答
取消 提交回答
  • ROW_NUMBER() 可能是最简单的解决方案:

    select f.*
    from (select f.*,
                 row_number() over (partition by f.id, f.year order by f.date desc) as seqnum
          from #foo f
          where f.date <= @date
         ) f
    where seqnum = 1;
    
    

    这基本上与版本性能相同。

    2020-01-04 15:30:26
    赞同 展开评论 打赏
问答地址:
问答排行榜
最热
最新

相关电子书

更多
低代码开发师(初级)实战教程 立即下载
冬季实战营第三期:MySQL数据库进阶实战 立即下载
阿里巴巴DevOps 最佳实践手册 立即下载