不同频率表之间的连接

SM4*_*SM4 3 sql-server-2008 join sql-server greatest-n-per-group

假设我有两个表DailyTableQuarterlyTable,每个表都有 3 列:IDDateValue

顾名思义,DailyTable存储数据的频率是每天,而QuarterlyTable存储数据的频率是季度。

如何连接这两个表,以便根据IDDate 将每个表中的最新(时间点)数据结合起来获得每日结果?

每日表

    ID   |  Date   |    Value  |
---------+---------+------------
    1    |1/1/2010 |     10    |
    1    |1/2/2010 |     15    |
              ... 
    1    |3/1/2010 |     20    |
              ... 
    1    |4/1/2010 |     30    |
Run Code Online (Sandbox Code Playgroud)

季表

    ID   |  Date   |    Value  |
---------+---------+------------
    1    |1/1/2010 |   1000    |
    1    |4/1/2010 |   2000    |
              ... 
Run Code Online (Sandbox Code Playgroud)

结果

    ID   |  Date   |    Value  |    Most Recent Quarterly Value
---------+---------+-------------------------------------------
    1    |1/1/2010 |     10    |             1000
    1    |1/2/2010 |     15    |             1000
              ... 
    1    |3/1/2010 |     20    |             1000
              ... 
    1    |4/1/2010 |     30    |             2000
Run Code Online (Sandbox Code Playgroud)

我正在处理财务数据,其中日表存储股票价格、交易量等,而季度表存储财务信息,例如净收入、收入。季度数据的更新频率取决于每个公司,因此假设每个季度有 90 天的间隔是不安全的。

开始和结束日期取决于 ID。QuarterStart 日期是每个 ID 不同的收益公布日期。该表有 3,000 个 ID。QuarterEnd 日期只是下一个 QuarterStart 日期 - 1 个工作日(在金融行业,Fiscal 和 Calendar 季度是两个相似但不完全相同的术语。两者都是季度,但日历年基于固定的日期范围,而 Fiscal 则基于公告) .

我正在寻找不需要创建和维护另一个表的解决方案。

Geo*_*son 5

这是一个解决方案,用于CROSS APPLY查找在每日日期或之前结束的最新季度的值。如果您的表由 索引(ID, Date),则此查询将非常有效,只需一行查找每个每日日期的季度值。

此解决方案也不需要日历表,并且不对季度的持续时间进行假设。但是,它确实假设您的季度表中没有空白。例如,如果您缺少一年中的季度,则解决方案会将“最近一个季度”标识为一年前发生的季度。这可能完全没问题,但您至少应该意识到这个假设。

CREATE TABLE #DailyTable (ID INT, DailyTableDate DATE, Value INT)
CREATE TABLE #QuarterlyTable (ID INT, QuarterlyTableDate DATE, Value INT)
ALTER TABLE #QuarterlyTable ADD UNIQUE CLUSTERED (ID, QuarterlyTableDate)

INSERT INTO #DailyTable (ID, DailyTableDate, VALUE) VALUES (1,'2010-01-01',10)
INSERT INTO #DailyTable (ID, DailyTableDate, VALUE) VALUES (1,'2010-02-01',15)
INSERT INTO #DailyTable (ID, DailyTableDate, VALUE) VALUES (1,'2010-03-01',20)
INSERT INTO #DailyTable (ID, DailyTableDate, VALUE) VALUES (1,'2010-04-01',30)

INSERT INTO #QuarterlyTable (ID, QuarterlyTableDate, VALUE) VALUES (1,'2010-01-01',1000)
INSERT INTO #QuarterlyTable (ID, QuarterlyTableDate, VALUE) VALUES (1,'2010-04-01',2000)

SELECT d.ID,
    d.DailyTableDate AS Result_Date,
    d.Value,
    qt.Value AS Most_Recent_Quarterly_Values
FROM #DailyTable AS d
CROSS APPLY (
    -- Find the value for latest quarter that ended on or before the daily date
    SELECT TOP 1 q.Value
    FROM #QuarterlyTable q
    WHERE q.ID = d.ID
        AND q.QuarterlyTableDate <= d.DailyTableDate
    ORDER BY q.QuarterlyTableDate DESC
) qt
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明