如何在单个语句中在SQL中更新时按顺序更新并查询更新的字段

时间:2015-05-04 14:02:09

标签: sql sql-server sql-server-2008 tsql

我需要计算数据库中的红利因子,一般方法所需的基本计算是row2 field2 = (row2's field1) * (row1's field2),其中field2是我需要同时更新和查询的值,即我计算了一行,我需要该行前一行的计算值。

现在我有一个带有所有值的临时表,现在我需要计算最终值,但是当我尝试这个时:

    UPDATE
        #temp
    SET
        field2 = IsNull(
            (SELECT d2.field2 * d.field1 FROM #temp AS d2 WHERE d2.rowNr = d.rowNr - 1)
            ,d.field1
        )
    FROM
        #temp as d  
    ;

它始终看到field2始终为NULL并且使用默认操作,它应该仅针对第一行。

现在目前我只知道两种方法:

  1. 使用光标
  2. 循环#temp
  3. 使用while语句并以这种方式循环遍历表(我选择了这个,因为我认为将光标用于最大10-20行的小表是没有意义的)
  4. 但我仍然希望将其纳入单一声明,但我不知道如何做到这一点。我正在使用MS SQL 2008 R2。

    修改

    这是我正在使用的实际数据:(注意,在计算之前所有field2值都为NULL且数据类型为 money

    field1      field2(expected values)
    ------      ----------------------
    1,033       1,033
    1,0363      1,0705
    1,0558      1,1302
    1,0157      1,1479
    1,0188      1,1695
    1,026       1,1999
    1,0286      1,2342
    1,0323      1,2741
    1,0319      1,3147
    

2 个答案:

答案 0 :(得分:2)

好的,如果我理解这一点,你想找到基于之前计算过的field2行的field2,这样你就需要某种形式的循环或递归。试试这个递归解决方案:

设置表

self

计算值

IF OBJECT_ID('tempdb..#temp') IS NOT NULL
    DROP TABLE #temp;

DECLARE @yourTable TABLE (ID INT,field1 INT, field2 INT);
INSERT INTO @yourTable(ID,field1,field2)
VALUES  (1111,11,11),(2222,22,22),(3333,33,33);


SELECT  ROW_NUMBER() OVER (ORDER BY ID) rowNr,
        ID,
        field1,
        field2 INTO #temp
FROM @yourTable;

实际更新

WITH cte_recursion
AS
(
    SELECT  TOP 1
            rowNR,
            ID,
            field1,
            field2,
            field1 AS dividend_factor
    FROM #temp A
    ORDER BY rowNr

    UNION ALL

    SELECT  B.rowNr,
            B.ID,
            B.field1,
            B.field2,
            B.field1 * A.dividend_factor
    FROM cte_recursion A
    INNER JOIN #temp B
    ON A.rowNr = B.rowNr - 1
)

结果:

UPDATE @yourTable
SET field2 = B.dividend_factor
FROM @yourTable A
INNER JOIN cte_recursion B
    ON A.ID = B.ID
OPTION (MAXRECURSION 0)

SELECT *
FROM @yourTable

就我个人而言,我不会使用此更新,因为您必须不断确保数据更新到目前为止。我更倾向于使用我用来计算值的CTE并将其放在视图中,以便您知道值始终是最新的,并且您不必担心运行它。除非值已更新,否则实际表中的dividend_factor列将为NULL,否则为NULL。只是我的两美分

答案 1 :(得分:1)

UPDATE d1
   SET d1.field2 = IsNull(d2.field2 * d1.field1, d1.field1) 
  FROM #temp AS d1 
  left outer join #temp AS d2  
    on d2.rowNr = d1.rowNr - 1

魔术

select d1.field1, EXP(SUM(LOG(d2.field1))) 
  from #temp AS d1 
  join #temp AS d2 
    on d2.rowNr <= d1.rowNr 
 group by d1.field1
op声称错误答案 为自己考试

drop table #temp; 
create table #temp (ID int, val money);
insert into #temp (ID, val) values 
  (1, 1.033)
, (2, 1.0363)     
, (3, 1.0558)      
, (4, 1.0157)     
, (5, 1.0188)     
, (6, 1.026)      
, (7, 1.0286)    
, (8, 1.0323)    
, (9, 1.0319);    
SELECT TOP 10  [t1].[ID], EXP(SUM(LOG([t2].[val]))) 
  from #temp AS t1 
  join #temp AS t2 
    on t2.[ID] <= t1.[ID] 
 group by t1.[ID] 
 order by t1.[ID]