更新查询以更新“其他记录之间的记录”?

时间:2012-03-09 21:46:30

标签: sql sql-server-2008

样本表:

 N  ProductName          Cost          Type            TOTAL

 1  ProductX             3             Checker  
 2  Product0             5             TOY
 3  Product1             5             TOY
 4  Product2             8             TOY

行2,3,4需要Type = Checker +当前行成本进入TOTAL列。因此第2行将是8,3将是8,而4将是11

 5  ProductZ             10            Checker         
 6  Product3             5             TOY
 7  Product4             9             TOY
 8  Product5             18            TOY
 9  Product6             25            TOY

同样,这些需要将ProductZ的成本添加到其总数中。因此第6行将是15,7将是19,依此类推。他们无法返回并在第1行引用ProductY。

数据集并不总是相同,并且数据集中可能有更多“Checker”类型的项目。

当只有一个时,显然效果很好。但是当有多个问题时,产品总数是错误的,因为它使用了错误的“Checker”值。

3 个答案:

答案 0 :(得分:2)

我认为此查询有效。

WITH toysAndCheckers AS
(
SELECT n AS toy, (SELECT top 1 lowerCheckers.n From sampleTable AS lowerCheckers
        WHERE lowerCheckers.N < theToys.N
        AND lowerCheckers.[type] = 'Checker'
        ORDER by n desc) AS matchingChecker

FROM sampleTable AS theToys
WHERE theToys.[type] = 'TOY'
),
toyCostAdjustments AS
(SELECT toy, cost AS checkerAdjustment
FROM toysAndCheckers 
JOIN sampleTable
    ON MatchingChecker = n
)       
MERGE sampleTable
USING
toyCostAdjustments
ON n = toy
WHEN MATCHED THEN UPDATE
SET total = cost + CheckerAdjustment
;

第一个CTE,“toysAndCheckers”,为每个玩具获得最高的CHECKER行的N,同时仍低于所讨论的TOY。第二个只是用cheker的成本替换了检查器的N.然后你有一个简单的合并。假设N列是唯一的,您将永远不会有多个匹配。

答案 1 :(得分:1)

这应该有效:

with Numbered as (
  select
    (select top (1) Cost from T as T2
     where T2.N <= T.N
       and T2.Type = 'Checker'
     order by N) as fv,
    *
  from T
)
  update Numbered set 
    TOTAL = Cost + fv
  where Type <> 'Checker';

你没有说'Checker'行的TOTAL应该是什么,所以我把它留给了NULL。

答案 2 :(得分:0)

我认为没有办法以我的首选方式做到这一点 - 以基于集合的方式。

你可以随时使用光标 - 它不是高性能或任何东西,但它可以工作。如果这只是一次性的,那你就没事了。如果您经常需要这样做,您可能希望继续寻找更好的解决方案:

-- declare a table variable for testing
DECLARE @sample TABLE (Num INT PRIMARY KEY, ProductName VARCHAR(50), Cost INT, ProdType VARCHAR(10), Total INT)

-- insert some data    
INSERT INTO @sample VALUES
    (1, 'ProductX', 3, 'Checker', NULL),
    (2, 'Product0', 5, 'TOY', NULL),
    (3, 'Product1', 5, 'TOY', NULL),
    (4, 'Product2', 8, 'TOY', NULL),
    (5, 'ProductZ', 10, 'Checker', NULL),
    (6, 'Product3', 5, 'TOY', NULL),
    (7, 'Product4', 9, 'TOY', NULL),
    (8, 'Product5', 18, 'TOY', NULL),
    (9, 'Product6', 25, 'TOY', NULL),
    (10, 'ProductY', 15, 'Checker', NULL),
    (11, 'Product7', 15, 'TOY', NULL),
    (12, 'Product8', 12, 'TOY', NULL),
    (13, 'Product9', 5, 'TOY', NULL)

-- declare the cursor, specify that we want to UDPATE the Total column   
DECLARE SampleCursor CURSOR KEYSET FOR
    SELECT Cost, Prodtype
    FROM @sample
    ORDER BY Num
    FOR UPDATE OF Total

-- declare and initialize variables    
DECLARE @Cost INT, @LastCheckerCost INT, @ProdType VARCHAR(10)

SET @LastCheckerCost = 0

-- open cursor and iterate over data set    
OPEN SampleCursor 

FETCH NEXT FROM SampleCursor INTO @Cost, @ProdType

-- while we have data......  
WHILE @@FETCH_STATUS = 0
BEGIN
    -- if we have a "Checker" row -> remember that value for later
    IF @ProdType = 'Checker'
        SET @LastCheckerCost = @Cost

    ELSE 
        -- if we have a "normal" row, update the Total column
        UPDATE @sample
        SET Total = @LastCheckerCost + @Cost
        WHERE CURRENT OF SampleCursor

    -- get next set of data    
    FETCH NEXT FROM SampleCursor INTO @Cost, @ProdType
END

-- close and clean up cursor
CLOSE SampleCursor 
DEALLOCATE SampleCursor

-- inspect results
SELECT * FROM @Sample