SQL查找匹配率与生效日期

时间:2018-01-12 23:58:51

标签: sql-server

在SQL Server 2014中,我有一个按日期排序的记录表。这是它的简化版本。

CREATE TABLE [SomeTrip] (
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [TripDate] [date] NOT NULL,
    CONSTRAINT [SomeTrip_PK] PRIMARY KEY NONCLUSTERED ([ID] ASC)
);

对于这些记录中的每一个,EffectiveDate上生效的各种项目有多种费率。这是该表的简化版本:

CREATE TABLE [SomeRates] (
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [EffectiveDate] [date] NOT NULL,
    [Rate1] [real] NOT NULL DEFAULT ((0)),
    [Rate2] [real] NOT NULL DEFAULT ((0)),
    [Rate3] [real] NOT NULL DEFAULT ((0)),
    [Rate4] [real] NOT NULL DEFAULT ((0)),
    CONSTRAINT [SomeRates_PK] PRIMARY KEY NONCLUSTERED ([ID] ASC)
);

以下是这两个表的一些示例数据:

INSERT INTO SomeRates (EffectiveDate, Rate1, Rate2, Rate3, Rate4) VALUES
('2016-01-01', 2016.1, 2016.2, 2016.3, 2016.4),
('2017-01-01', 2017.1, 2017.2, 2017.3, 2017.4),
('2018-01-01', 2018.1, 2018.2, 2018.3, 2018.4);

INSERT INTO SomeTrip (TripDate) VALUES ('2018-01-03'), ('2017-11-15'), ('2016-06-30');

如果我想在已知日期选择旅行以及有效费率,我可以进行以下查询:

-- Select all trips and rate relative to a single date
select *
FROM SomeTrip
LEFT OUTER JOIN (SELECT TOP 1 * FROM SomeRates WHERE SomeRates.EffectiveDate <= '2017-12-15' ORDER BY SomeRates.EffectiveDate DESC) AS SomeRates ON 1=1;

这提供了以下数据:

ID  TripDate    ID  EffectiveDate  Rate1   Rate2   Rate3   Rate4
1   2018-01-03  2   2017-01-01     2017.1  2017.2  2017.3  2017.4
2   2017-11-15  2   2017-01-01     2017.1  2017.2  2017.3  2017.4
3   2016-06-30  2   2017-01-01     2017.1  2017.2  2017.3  2017.4

但是,我想显示在给定时间生效的价格相对于TRIP。 (实际上,我在选择中有很多其他计算取决于速率。)一个天真的,语法不正确的尝试是这样的:

-- Select all trips and rate relative to the trip's TripDate
select *
FROM SomeTrip
LEFT OUTER JOIN (SELECT TOP 1 * FROM SomeRates WHERE SomeTrip.TripDate >= SomeRates.EffectiveDate ORDER BY SomeRates.EffectiveDate DESC) AS SomeRates ON 1=1;

问题是SQL Server不允许从SomeRates上的内部查询访问SomeTrip的行。

这是我希望看到的结果:

ID  TripDate    ID  EffectiveDate  Rate1   Rate2   Rate3   Rate4
1   2018-01-03  3   2018-01-01     2018.1  2018.2  2018.3  2018.4
2   2017-11-15  2   2017-01-01     2017.1  2017.2  2017.3  2017.4
3   2016-06-30  1   2016-01-01     2016.1  2016.2  2016.3  2016.4

我觉得应该有一些解决方案可能使用PARTITION,但我不熟悉它来提出一些东西。提前谢谢!

1 个答案:

答案 0 :(得分:2)

OUTER APPLY非常适合此类问题。

SELECT *
FROM SomeTrip
 OUTER APPLY 
   (SELECT TOP 1 * 
      FROM SomeRates 
      WHERE SomeTrip.TripDate >= SomeRates.EffectiveDate 
      ORDER BY SomeRates.EffectiveDate DESC) AS SubQuery

如果你在TripDate和EffectiveDate列上放置索引,它也会为你节省一个伤害的世界。