在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,但我不熟悉它来提出一些东西。提前谢谢!
答案 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列上放置索引,它也会为你节省一个伤害的世界。