从前一个日期检索最后一个有效值

Retrieve the last valid value from a previous date

我有以下 table“费率”:

aDate realRate isBusinessDay
01-04-22 1.10 1
02-04-22 1.20 1
03-04-22 1.30 1
04-04-22 1.40 0
05-04-22 1.50 0
06-04-22 1.60 1
07-04-22 1.70 1
08-04-22 1.80 1
09-04-22 1.90 1
10-04-22 2.00 0
11-04-22 2.10 0
12-04-22 2.20 0
13-04-22 2.30 0
14-04-22 2.40 1
15-04-22 2.50 1
16-04-22 2.60 1
17-04-22 2.70 1
18-04-22 2.80 0
19-04-22 2.90 0
20-04-22 3.00 0
21-04-22 3.10 1

我需要构建一个查询,该查询将 return 用于非工作日的前一个已知工作日的汇率。 “useThisRate”列是查询所需的结果:

aDate realRate isBusinessDay useThisRate
01-04-22 1.10 1 1.10
02-04-22 1.20 1 1.20
03-04-22 1.30 1 1.30
04-04-22 1.40 0 1.30
05-04-22 1.50 0 1.30
06-04-22 1.60 1 1.60
07-04-22 1.70 1 1.70
08-04-22 1.80 1 1.80
09-04-22 1.90 1 1.90
10-04-22 2.00 0 1.90
11-04-22 2.10 0 1.90
12-04-22 2.20 0 1.90
13-04-22 2.30 0 1.90
14-04-22 2.40 1 2.40
15-04-22 2.50 1 2.50
16-04-22 2.60 1 2.60
17-04-22 2.70 1 2.70
18-04-22 2.80 0 2.70
19-04-22 2.90 0 2.70
20-04-22 3.00 0 2.70
21-04-22 3.10 1 3.10

请注意连续的非工作日天数未知。

任何帮助将不胜感激。

您可以执行一些 self-joins 和嵌入式子查询以使其工作。 我没有方便访问的 SQL 服务器,但查询如下所示。

SELECT aDate, realRate
  FROM Rates
 WHERE IsBusinessDay = 1
UNION ALL
SELECT sub.aDate, r3.realRate
  FROM Rates r3
        INNER JOIN (
            SELECT r1.aDate, 
                   (SELECT MAX(aDate) 
                      FROM Rates r2 
                     WHERE r2.aDate < r1.aDate 
                       AND r2.isBusinessDay = 1) as LastDate
              FROM Rates r1
             WHERE r1.IsBusinessDay = 0
             ) sub
            ON r3.aDate = sub.LastDate

基本上:

  • 取所有工作日(第一次查询) 加上所有 non-business 天。对于那些:
  • 对于每个 non-business 天,一个嵌入式子查询获取 MAX(),即小于 non-business 天的工作日。
  • 然后加入实际 table 以获得该工作日的费率。

请注意,如果 table 中的行数非常大,这样的嵌入式查询可能会很昂贵,但由于您似乎每天有 1 行,所以您不应该有数百万行。原因是因为它使用 r1 table 作为过滤条件,服务器必须 re-execute r1 中每一行的子查询。

可能最直观的方式是关联查询。

您要么想要 realRate,要么 if non-business 天是工作日且日期早于当前行的最近的 realRate。

select *,
  case when isBusinessDay = 1 then realrate
    else (
      select top(1) realrate
        from rates r2
        where r2.isBusinessDay = 1 and r2.aDate < r.adate
        order by adate desc
    ) 
  end UseThisRate
from rates r;

您已经有了一个很好的答案,但只是提供另一种思考方式,即使用 APPLY:

SELECT r.aDate, r.isBusinessDay, r.realRate,
  UseThisRate = CASE r.isBusinessDay 
    WHEN 0 THEN x.prevRate ELSE r.realRate END
FROM dbo.Rates AS r
OUTER APPLY 
(
  SELECT TOP (1) prevRate = r2.realRate 
    FROM dbo.Rates AS r2
    WHERE r2.isBusinessDay = 1
      AND r2.aDate < r.aDate
    ORDER BY r2.aDate DESC
) AS x;