T-SQL计算每个项目最早和最晚之间的增加或减少百分比

时间:2018-02-19 20:32:33

标签: sql sql-server tsql

我有一个如下表格,我试图在T-SQL中运行查询,根据日期列获取每个project_id的最早和最新成本,并计算成本增加或减少百分比并返回数据集显示在第二个表格中(我在这个问题中简化了表格)。

project_id  date        cost
-------------------------------
123          7/1/17     5000
123          8/1/17     6000
123          9/1/17     7000
123         10/1/17     8000
123         11/1/17     9000
456          7/1/17    10000
456          8/1/17     9000
456          9/1/17     8000
876          1/1/17     8000
876          6/1/17     5000
876          8/1/17    10000
876         11/1/17     8000

结果:

(编辑:修正了结果)

project_id        "cost incr/decr pct"
------------------------------------------------
123                80% which is (9000-5000)/5000
456                -20%
876                 0%

无论我运行什么查询,我都会重复。

这就是我的尝试:

select distinct 
    p1.Proj_ID, p1.date, p2.[cost], p3.cost,
    (nullif(p2.cost, 0) / nullif(p1.cost, 0)) * 100 as 'OVER UNDER'
from
    [PROJECT] p1
inner join
    (select  
         [Proj_ID], [cost], min([date]) min_date
     from
         [PROJECT]
     group by 
         [Proj_ID], [cost]) p2 on p1.Proj_ID = p2.Proj_ID
inner join
    (select  
         [Proj_ID], [cost], max([date]) max_date
     from
         [PROJECT]
     group by 
         [Proj_ID], [cost]) p3 on p1.Proj_ID = p3.Proj_ID
where 
    p1.date in (p2.min_date, p3.max_date)

3 个答案:

答案 0 :(得分:2)

不幸的是,SQL Server没有first_value()聚合功能。但它确实具有分析功能。所以,你可以这样做:

select distinct project_id,
       first_value(cost) over (partition by project_id order by date asc) as first_cost,
       first_value(cost) over (partition by project_id order by date desc) as last_cost,
       (first_value(cost) over (partition by project_id order by date desc) /
        first_value(cost) over (partition by project_id order by date asc)
       ) - 1 as ratio
from project;

如果cost是整数,则可能需要转换为带小数位的表示。

答案 1 :(得分:1)

您可以在SQL 2012之前使用row_numberOUTER APPLY而不是top 1 ...

select 
min_.projectid,
latest_.cost - min_.cost [Calculation]
from
(select 
 row_number() over (partition by projectid order by date) rn
 ,projectid
 ,cost
 from projectable) min_   -- get the first dates per project
outer apply (
select 
 top 1 
   cost
 from projectable 
where 
projectid = min_.projectid    -- get the latest cost for each project
order by date desc
) latest_
where min_.rn = 1

答案 2 :(得分:0)

这可能会更好一点

;with costs as (
    select      *,
                ROW_NUMBER() over (PARTITION BY project_id ORDER BY date) mincost,
                ROW_NUMBER() over (PARTITION BY project_id ORDER BY date desc) maxcost
    from        table1
)
select      project_id,
            min(case when mincost = 1 then cost end) as cost1,
            max(case when maxcost = 1 then cost end) as cost2,
            (max(case when maxcost = 1 then cost end) - min(case when mincost = 1 then cost end)) * 100 / min(case when mincost = 1 then cost end)  as [OVER UNDER]
from        costs a 
group by    project_id