根据购买日期和有效价格日期选择正确的价格

时间:2014-12-06 22:48:26

标签: sql-server

我需要一个查询来查找购买时商品的价格;价格随时间而变化。 我有两个由外键链接的表:

table Albums:
ID  Name    PurchaseDate
1   Album1  2014-05-14
2   Album2  2014-05-14
3   Album3  2014-05-14

table Prices:
ID  AlbumID Price   EffDate
1   1       5.00    2014-01-01
2   2       5.00    2014-01-01
3   3       5.00    2014-01-01
4   3       60.00   2014-04-25
5   3       700.00  2014-12-12

当我使用此查询加入表时:

select a.ID, a.Name, a.PurchaseDate, p.Price, p.EffDate
from Albums a
inner join Prices p
on a.ID=p.AlbumID;

我得到以下结果:

ID  Name    PurchaseDate  Price  EffDate
1   Album1  2014-05-14    5.00   2014-01-01
2   Album2  2014-05-14    5.00   2014-01-01
3   Album3  2014-05-14    5.00   2014-01-01
3   Album3  2014-05-14    60.00  2014-04-25
3   Album3  2014-05-14    700.00 2014-12-12

问题是Album3的多重结果。将来EffDate很容易摆脱记录:

select a.ID, a.Name, a.PurchaseDate, p.Price, p.EffDate
from Albums a
inner join Prices p
on a.ID=p.AlbumID 
where p.EffDate <= a.PurchaseDate;

这给出了以下结果:

ID  Name    PurchaseDate  Price  EffDate
1   Album1  2014-05-14    5.00   2014-01-01
2   Album2  2014-05-14    5.00   2014-01-01
3   Album3  2014-05-14    5.00   2014-01-01
3   Album3  2014-05-14    60.00  2014-04-25

但是我需要为每个专辑选择一个记录,即给出2014-05-14的PurchaseDates时最新EffDate的记录(即2014-04-25的Album3为60.00)。 我心想,#34;这应该很容易!&#34;但我无法弄明白!我尝试过DISTINCT,用MAX(EffDate),公用表表达式,ROW_NUMBER()和PARTITION BY和ORDER BY子句聚合,FIRST_VALUE(Price)OVER(...),以及所有这些的组合,我和# 39; m仍然难倒! (也可能只是简单的老哑!)以下是我的许多失败尝试中的两个:

尝试A:

WITH cte AS
(
    select a.ID, a.Name, a.PurchaseDate, p.Price, p.EffDate
    from Albums a
    inner join Prices p
    on a.ID=p.AlbumID
    where p.EffDate <= a.PurchaseDate
)
select ID, Name, PurchaseDate, Price, MaxED = (select max(EffDate) from cte)
from cte;

---此查询和其他类似变体提供与上一个列表完全相同的结果!聚合函数max(EffDate)显然对CTE结果没有影响?!

尝试B:

select a.ID, a.Name, a.PurchaseDate, p.Price, p.EffDate, pseq
from Albums a
inner join 
    (select p.*, row_number() over (partition by AlbumID order by EffDate) as pseq
    from Prices p) p
on a.ID=p.AlbumID
where p.EffDate <= a.PurchaseDate;

---此查询也提供与上面完全相同的结果(额外列&#39; pseq&#39;除外)!

here等其他类似帖子中的解决方案与我的情况无关。

对于长篇文章感到抱歉,但我认为清楚地设置示例和我的要求以及我的一些失败很重要。请帮助!

P.S。:我正在使用MS SQLEXPRESS 2014和SSMS。是的,我的实际表和查询比这个例子复杂得多,但是这个例子尽可能简洁地呈现了我的基本问题。

1 个答案:

答案 0 :(得分:0)

这样的事情可能会给你实际价格:

select 
a.ID, 
a.Name, 
a.PurchaseDate, 
(select top 1 p.Price from Prices p where p.AlbumId = a.Id and p.EffDate <= a.PurchaseDate  order by p.EffDate desc) as 'Price'
from Albums a

输出:

ID          Name                 PurchaseDate            Price
----------- -------------------- ----------------------- ---------------------------------------
1           Album1               2014-05-14 00:00:00.000 5.00
2           Album2               2014-05-14 00:00:00.000 5.00
3           Album3               2014-05-14 00:00:00.000 60.00

或者如果您需要实际加入价格以获得其他列,您可以这样做:

select 
* 
from Albums a
left join Prices p on 
(
    a.ID = p.AlbumID and 
    p.ID = (select top 1 pp.Id from Prices pp where pp.AlbumId = a.Id and pp.EffDate <= a.PurchaseDate  order by pp.EffDate desc)
)

获得此输出:

ID          Name                 PurchaseDate            ID          AlbumID     Price                                   EffDate
----------- -------------------- ----------------------- ----------- ----------- --------------------------------------- -----------------------
1           Album1               2014-05-14 00:00:00.000 1           1           5.00                                    2014-01-01 00:00:00.000
2           Album2               2014-05-14 00:00:00.000 2           2           5.00                                    2014-01-01 00:00:00.000
3           Album3               2014-05-14 00:00:00.000 4           3           60.00                                   2014-04-25 00:00:00.000