TSQL计算具有重叠日期范围的记录的每日总和

时间:2013-02-07 10:17:51

标签: tsql group-by datediff

我有3个表,1(PortfolioInstrument)持有在portoflio中持有的工具(工具),持有(持有)跨越日期范围(DateAdded,DateRemoved)。 另一个(价格)持有每种工具(工具)的每日(TradeDate)收盘价([关闭])。 第三个可能有用,(CalcDate)保存我们重新计算持股的日期(CalcDate),并从投资组合中添加和删除工具。

SELECT SUM([Close]*Holding), TradeDate 
FROM Price p1 INNER JOIN PortfolioInstrument pio ON pio.Instrument = p1.Instrument 
AND pio.Portfolio = 3 
WHERE EXISTS (SELECT TradeDate FROM Price p 
INNER JOIN PortfolioInstrument pi ON pi.Instrument = p.Instrument AND Portfolio = 3
WHERE TradeDate >= pi.DateAdded AND 
(TradeDate < pi.DateRemoved OR pi.DateRemoved IS NULL) 
AND p1.ID = p.ID GROUP BY TradeDate) GROUP BY TradeDate

以下是PortfolioInstrument数据集的示例

ID  Portfolio Instrument Holding    DateAdded               DateRemoved

16256   3   410     714.28571       2007-10-01 00:00:00.0   2007-11-01 00:00:00.0
16257   3   611     564.97174       2007-10-01 00:00:00.0   2007-11-01 00:00:00.0
16258   3   538     1,797.75281     2007-10-01 00:00:00.0   2007-11-01 00:00:00.0
...
16302   3   5352    1,067,319.75    2008-02-01 00:00:00.0   2008-04-01 00:00:00.0
16303   3   5353    1,057,800.875   2008-02-01 00:00:00.0   2008-04-01 00:00:00.0
16304   3   11952   0               2008-02-29 00:00:00.0   2008-04-01 00:00:00.0
16305   3   11952   261,484,400     2008-04-01 00:00:00.0   2008-05-01 00:00:00.0
...
16315   3   8374    14,199.99902    2009-01-30 00:00:00.0   <null>
16316   3   11952   246,102,960     2009-01-30 00:00:00.0   2009-02-27 00:00:00.0
16317   3   11952   246,148,912     2009-02-27 00:00:00.0   2009-04-01 00:00:00.0

这个问题在于它包含所有拥有DateRemoved&lt; TradeDate所以每个重新计算日期都有一个跳转,它们应该从集合中删除。看看Stackoverflow上的各种DateDiff方法,但在这种情况下无法解决如何使用它们进行分组的问题。另请注意,现金工具(工具= 11952)在某个时刻进入投资组合,然后每个月获得一个条目,因为您可以看到它在几个月内减少到0,这在我生产的SQL中我认为无关紧要

THX。

大卫

2 个答案:

答案 0 :(得分:1)

为什么要使用相同连接的另一个实例并不是很清楚。如果要排除DateRemoved <= TradeDate中的特定馆藏,您可以直接在WHERE子句中检查:

SELECT SUM(p1.[Close]*pio.Holding), TradeDate 
FROM Price p1
INNER JOIN PortfolioInstrument pio
ON pio.Instrument = p1.Instrument AND pio.Portfolio = 3 
WHERE p1.TradeDate >= pio.DateAdded
  AND (p1.TradeDate < pio.DateRemoved OR pio.DateRemoved IS NULL) 
GROUP BY p1.TradeDate
;

但是,如果要丢弃相同TradeDate行的整个,其中至少有一行满足条件DateRemoved <= TradeDate,则可以使用HAVING子句,像这样:

SELECT SUM(p1.[Close]*pio.Holding), TradeDate 
FROM Price p1
INNER JOIN PortfolioInstrument pio
ON pio.Instrument = p1.Instrument AND pio.Portfolio = 3 
GROUP BY p1.TradeDate
HAVING COUNT(CASE WHEN p1.TradeDate <= pio.DateRemoved) THEN 1 END) = 0
;

与适用于各行的WHERE子句不同,HAVING是针对一组行进行评估的。在这种情况下,COUNT()函数用于计算组中有多少行p1.TradeDate <= pio.DateRemoved。如果至少有一个,那么该组将从输出中被丢弃,因为我在这里假设的要求是没有这样的行。

答案 1 :(得分:0)

无法找到前进的方法,最终拉入原始行并在代码中进行计算。