2014-12-06 77 views
2

我需要一个查询来查找购买时物品的价格;价格随时间变化。 我有两个表的外键链接:选择正确的价格给定购买日期和生效日期

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 

但我需要选择每一张专辑只有一条记录,即一个最新的EffDate给予了2014-05-14的购买日期(即2014-04-25的Album3为60.00)。 我心想,“应该很容易!”但我无法弄清楚它!我试过DISTINCT,与MAX(EffDate),公共表表达式,ROW_NUMBER()与分区BY和ORDER BY子句,FIRST_VALUE(价格)OVER(...)和所有这些的组合,我仍然难倒! (!大概也只是普通的老哑)这里是我的两个许多失败的尝试:

尝试:

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; 

---此查询还给出了完全相同的结果如上(除了额外的列 'PSEQ')!

其他类似帖子的解决方案,如here没有与我的情况。

对不起,对于这篇较长的文章,但我认为清楚地设置示例和我的要求以及我的一些失败很重要。请帮忙!

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

回答

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 
+0

的建议Romero-谢谢,但它不工作。查询的结果是:1 \t Album1 \t 2014年5月14日\t 60.00; \t Album2 2014年5月14日\t 60.00; \t Album3 2014年5月14日\t 60.00; – MDGeek 2014-12-06 23:09:31

+0

刚刚添加了另一种方法,实际加入。不是最优雅的查询,但他们确实工作:) – 2014-12-06 23:36:41

+0

它的工作原理!谢谢你太多了!我在这个愚蠢的问题上浪费了大部分时间! – MDGeek 2014-12-06 23:38:03