特定日期之前不同值的乘积

时间:2018-07-23 09:13:27

标签: sql sql-server

我有一个带模式的表:

date     | item_id | factor
----------------------
20180710 | 1  | 0.1
20180711 | 1  | 0.1
20180712 | 1  | 2
20180713 | 1  | 2
20180714 | 1  | 2
20180710 | 2  | 0.1
20180711 | 2  | 0.1
20180712 | 2  | 5
20180713 | 2  | 5
20180714 | 2  | 10

每个item_id的因子可以在任何日期更改。在每个日期,我需要计算该日期(包括该日期)之前每个item_id的所有不同因子的乘积,因此上表的最终输出应为:

date     | id | cumulative_factor
20180710 | 1  | 0.1
20180711 | 1  | 0.1
20180712 | 1  | 0.2
20180713 | 1  | 0.2
20180714 | 1  | 0.2
20180710 | 2  | 0.1
20180711 | 2  | 0.1
20180712 | 2  | 0.5
20180713 | 2  | 0.5
20180714 | 2  | 5

逻辑:

在20180711上,对于id = 1,唯一因子仅为0.1,因此累积因子为0.1。

在20180714上,对于id = 1,不同因子是0.1和2,因此累积因子是0.1 * 2 = 0.2。

在20180714上,对于id = 2,不同因子为0.1、5和10,因此累积因子为0.1 * 5 * 10 = 5。

我尝试过

select a.id, a.date, b.cum_factor   
from factor_table a
left join (
    select id, date, ISNULL(EXP(SUM(distinct log_factor)),1) as cum_factor 
    from factor_table
    where date < a.date  
    ) b
    on a.id=b.id and a.date = b.date

但是我得到了错误

  

找不到日期

2 个答案:

答案 0 :(得分:1)

SQL Server中没有产品聚合函数。

但是,您可以使用EXP ( SUM ( LAG ( value ) ) )

进行仿真

请参考在线查询以获取评论

; with 
cte as
(
    -- this cte set the factor to 1 if it is same as previous row
    -- as you wanted `product of distinct`
    select  *, 
            factor2 = CASE WHEN LAG(factor) OVER (PARTITION BY id 
                                                      ORDER BY [date]) IS NULL
                           OR   LAG(factor) OVER (PARTITION BY id 
                                                      ORDER BY [date]) <> factor                
                           THEN factor
                           ELSE 1
                           END
    from    factor_table
),
cte2 as
(
    -- this cte peform SUM( LOG ( factor ) ) only. except EXP()
    select  *, factor3 = SUM(LOG(factor2)) OVER (PARTITION BY id 
                                                     ORDER BY [date])
    from    cte
)
-- EXP() is not a window function, so it has to do it in separately in another level
select  *, EXP(factor3) as cumulative_factor
from    cte2

注意:LAG()需要SQL Server 2012或更高版本

答案 1 :(得分:1)

乘以与众不同的因子似乎有些错误。您可以使用窗口函数轻松地表达这一点:

select f.id, f.date, f.cum_factor  
       exp(sum(distinct log(log_factor) over (partition by f.id order by f.date)))  
from factor_table f;

要解决distinct上的限制:

select f.id, f.date, f.cum_factor  
       exp(sum(log(case when seqnum = 1 then log_factor end) over (partition by f.id order by f.date)))  
from (select t.*,
             row_number() over (partition by id, log_factor order by date) as seqnum
      from factor_table f
     ) f;