SQL Server:根据上一行/ id中的值计算列值

时间:2020-11-11 16:49:10

标签: sql sql-server

我有一个希望解决的简单问题,但令人困惑的是。我的表可以使用以下sql创建:

CREATE TABLE test
(
     [Id] [int] IDENTITY(1, 1) NOT NULL, 
     [lang] varchar(13), 
     [TotalProjectCost] [decimal](16, 2)
);

INSERT INTO test ([lang], [TotalProjectCost])
VALUES
    ('en',  CAST(341412.00 AS Decimal(16, 2))),
    ('es-mx',  CAST(342.00 AS Decimal(16, 2))),
    ('en',  CAST(341412.00 AS Decimal(16, 2))),
    ('es-mx',  CAST(34.00 AS Decimal(16, 2))),
    ('en',  CAST(341412.00 AS Decimal(16, 2))),
    ('es-mx',  CAST(34.00 AS Decimal(16, 2)));

看起来像这样:

enter image description here

这基本上是货币转换任务(在此示例中es-mx行中的成本是任意的)。我想做的是用es-mx的lang更新行的所有TotalProjectCost值:对于这些行,我希望将值计算为上一个' zh_CN * 15.8735。

我的实际表的设置方式是,值总是成对提交(一个en,一个es-mx)...因此,奇数Ids应该始终为en,即使偶数也应始终为es-mx。如您所见,可能有很多方法可以解决这个问题,也许这就是为什么我很难知道从哪里开始。

我有点想这个选择语句:

TotalProjectCost

但是我仍然无法真正获得计算正确值的更新。

我对此表示感谢!我尝试在板上找到一个与我的情况有些相符的示例,但它们似乎比我要完成的工作要复杂得多。

3 个答案:

答案 0 :(得分:2)

在可更新的CTE中使用LAG()寡妇功能:

WITH cte AS (
  SELECT *, LAG([TotalProjectCost]) OVER (ORDER BY [Id]) prev_cost 
  FROM test
)
UPDATE cte 
SET [TotalProjectCost] = 15.8735 * prev_cost
WHERE [lang] = 'es-mx'

请参见demo
结果:

> Id | lang  | TotalProjectCost
> -: | :---- | ---------------:
>  1 | en    |        341412.00
>  2 | es-mx |       5419403.38
>  3 | en    |        341412.00
>  4 | es-mx |       5419403.38
>  5 | en    |        341412.00
>  6 | es-mx |       5419403.38

答案 1 :(得分:1)

尝试

update table1
   set [TotalProjectCost] = table2.[TotalProjectCost] * 15.8735
from test as table1
inner join test as table2 on table1.[ID] = (table2.[ID] + 1)
    and table2.[lang] = 'en'

答案 2 :(得分:1)

您可以使用横向连接:

select t.*,
       (case when t.lang = 'es-mx' then t2.TotalProjectCost * 15.8735
             else t.TotalProjectCost
        end) as imputed_TotalProjectCost
from t cross apply
     (select t2.*
      from t t2
      where t2.lang = 'en' and t2.id <= t.id
      order by t2.id desc
     ) t2;

如果您想更改数据,可以轻松地将其合并到更新中:

update t
    set t.TotalProjectCost = t2.TotalProjectCost * 15.8735
    from t cross apply
         (select t2.*
          from t t2
          where t2.lang = 'en' and t2.id <= t.id
          order by t2.id desc
         ) t2
    where t.lang = 'es-mx'