按正/负值汇总v.2

时间:2015-08-30 15:43:35

标签: sql sql-server

我发布了几个主题,每个查询都有一些问题:(更改了表格和示例以便更好地理解

我有一个名为PROD_COST的表,有5个字段

(ID,Duration,Cost,COST_NEXT,COST_CHANGE).

我需要额外的字段,称为" groups"用于聚合。

  1. 持续时间=价格有效的天数(1天= 1row)。
  2. 成本=当天的产品价格。
  3. -Cost_next = lead(cost,1,0)。
  4. Cost_change = Cost_next - 费用。
  5. 示例:

    +----+---------+------+-------------+-------+
    |ID  |Duration | Cost | Cost_change | Groups|
    +----+---------+------+-------------+-------+
    |  1 | 1       | 10   | -1,5        | 1     |
    |  2 | 1       | 8,5  | 3,7         | 2     |
    |  3 | 1       | 12.2 | 0           | 2     |
    |  4 | 1       | 12.2 | -2,2        | 3     |
    |  5 | 1       | 10   |  0          | 3     |
    |  6 | 1       | 10   | 3.2         | 4     |
    |  7 | 1       | 13.2 | -2,7        | 5     |
    |  8 | 1       | 10.5 | -1,5        | 5     |
    |  9 | 1       | 9    |  0          | 5     |
    | 10 | 1       | 9    |  0          | 5     | 
    | 11 | 1       | 9    | -1          | 5     |
    | 12 | 1       | 8    | 1.5         | 6     |
    +----+---------+------+-------------+-------+
    

    现在我需要通过Cost_change对(" Groups" field)进行分组。它可以是正数,负数或0值。 某种善意的人告诉我这个问题:

    select id, COST_CHANGE, sum(GRP) over (order by id asc) +1
    from
       (
        select    *, case when sign(COST_CHANGE) != sign(isnull(lag(COST_CHANGE) 
         over (order by id asc),COST_CHANGE)) and Cost_change!=0 then 1 else 0 end as GRP
        from PROD_COST
       ) X
    

    但是存在一个问题:如果两个正值或负值之间的值为0,则分别对它进行分组,例如:

     +-------------+--------+
     | Cost_change | Groups |
     +-------------+--------+
     | 9.262       |   5777 |
     | -9.262      |   5778 |
     | 9.262       |   5779 |
     | 0.000       |   5779 |
     | 9.608       |   5780 |
     | -11.231     |   5781 |
     | 10.000      |   5782 |
     +-------------+--------+
    

    我需要:

     +-------------+--------+
     | Cost_change | Groups |
     +-------------+--------+
     | 9.262       |   5777 |
     | -9.262      |   5778 |
     | 9.262       |   5779 |
     | 0.000       |   5779 |
     | 9.608       |   5779 | -- Here
     | -11.231     |   5780 |
     | 10.000      |   5781 |
     +-------------+--------+
    

    换句话说,如果两个正两个负值之间的值为0,那么它们应该在一个组中,因为序列:MINUS-0-0-MINUS - 无旋转。但是如果我有MINUS-0-0-PLUS,那么GROUPS应该是1-1-1-2,因为正值正在以负值旋转。 谢谢你的关注!

    我正在使用Sql Server 2012

1 个答案:

答案 0 :(得分:0)

我认为最好的方法是删除零,进行计算,然后重新插入它们。所以:

with pcg as (
      select pc.*, min(id) over (partition by grp) as grpid
      from (select pc.*,
                   (row_number() over (order by id) -
                    row_number() over (partition by sign(cost_change)
                                       order by id
                   ) as grp 
            from prod_cost pc
            where cost_change <> 0
           ) pc
     )
select pc.*, max(groups) over (order by id)
from prod_cost pc left join
      (select pcg.*, dense_rank() over (order by grpid) as groups
       from pcg
     ) pc
     on pc.id = pcg.id;

CTE根据组中的最低ID分配组标识符,其中组以实际符号更改为界。子查询将其转换为数字。外部查询然后累积最大值,以给0记录赋值。