【问题标题】:Update SQL Table based on column values根据列值更新 SQL 表
【发布时间】:2013-10-15 14:32:30
【问题描述】:

我有大量数据需要根据价格进行更新。很简单,Code/Size 1 中的商品的价格必须等于或小于 Code/Size 2。Code/Size 2 必须等于或小于 Code/Size 3,依此类推:

Item       Code   Size  Price   
-------------------------------
66227019    OTH     1   $466
66227019    OTH     2   $486
66227019    OTH     3   $476
66227019    OTH     4   $537

66227019    IVC     1   $458
66227019    IVC     2   $428
66227019    IVC     3   $458
66227019    IVC     4   $458

必须看起来像:

Item       Code   Size  Price   
-------------------------------
66227019    OTH     1   $466
66227019    OTH     2   $486
66227019    OTH     3   $486
66227019    OTH     4   $537

66227019    IVC     1   $458
66227019    IVC     2   $458
66227019    IVC     3   $458
66227019    IVC     4   $458

我尝试了一些自加入,但我基本上失去了理智。真诚感谢任何帮助。

谢谢!

【问题讨论】:

  • SQL-Server 或其他 DBMS?版本?
  • 我可能会失明,但您想要的结果有什么不同?
  • 如果有另一条具有相同商品和代码且尺寸较小且价格较高的记录,您想提高{商品、代码、尺寸}条目的价格?
  • @Andrew 一些价格已经提高 - 根据要求。
  • @ypercube 我正在使用 SQL Server 2012

标签: sql-server tsql sql-server-2012


【解决方案1】:

对于 SQL-Server 2012,您可以使用:

; WITH cte AS
( SELECT *,
         MaxPrice = MAX(Price) 
                    OVER (PARTITION BY Item, Code
                          ORDER BY Size
                          ROWS BETWEEN UNBOUNDED PRECEDING
                                   AND 1 PRECEDING
                         ) 
  FROM Products
) 
UPDATE cte
SET Price = MaxPrice
WHERE Price < MaxPrice ;

测试于 SQL-Fiddle

【讨论】:

  • 这成功了!再次感谢,我将不得不查找 UNBounded PRECEDING 和 1 PRECEDING 之间的行。以前从未见过那个。干杯!
【解决方案2】:

这能满足你的需要吗?

UPDATE LaterRec
SET Price = PrevRec.Price
FROM Data AS LaterRec
    INNER JOIN Data AS PrevRec ON LaterRec.Item = PrevRec.Item AND LaterRec.Code = PrevRec.Code AND PrevRec.Size < LaterRec.Size
WHERE
        PrevRec.Price > LaterRec.Price
    -- Disregard this entry if there's a record *between* PrevRec and LaterRec
    AND NOT EXISTS (SELECT * FROM Data AS Intrmdt WHERE LaterRec.Item = Intrmdt.Item AND LaterRec.Code = Intrmdt.Code AND Intrmdt.Size > PrevRec.Size AND Intrmdt.Size < LaterRec.Size)

【讨论】:

    【解决方案3】:

    答案是递归 CTE。不依赖于 SQL SERVER 版本。

        DECLARE @t TABLE
        (
            item        INT
            ,code       sysname
            ,SIZE       INT
            ,price      INT
        )
        INSERT INTO @t( item, code, SIZE, price )
                    SELECT 1,'oth',1,466
        UNION ALL   SELECT 1,'oth',2,486
        UNION ALL   SELECT 1,'oth',3,476
        UNION ALL   SELECT 1,'oth',4,537
    
        UNION ALL   SELECT 1,'ivc',1,458
        UNION ALL   SELECT 1,'ivc',2,428
        UNION ALL   SELECT 1,'ivc',3,458
        UNION ALL   SELECT 1,'ivc',4,458
    
        SELECT * FROM @t
    
        ;WITH cte1 (item,code,size,price,rownum1,rownum2)
        AS
        (
            SELECT *, ROW_NUMBER() OVER (PARTITION BY item,code ORDER BY item,code,SIZE) AS rownum1, ROW_NUMBER() OVER (ORDER BY item,code,SIZE) AS rownum2
            FROM @t
        ),  
        cte2 (item,code,size,price,rownum1,rownum2)
        AS
        (
            SELECT *
            FROM cte1 t1
            WHERE rownum2=1
    
            UNION ALL
    
            SELECT t1.item,t1.code,t1.size
                    ,CASE   WHEN t1.price>=t2.price THEN t1.price 
                            WHEN t1.price<t2.price THEN t2.price
                    END AS proce
                    ,t1.rownum1,t1.rownum2
            FROM cte2 t2
            JOIN cte1 t1
                ON t2.rownum2+1=t1.rownum2
        )
        SELECT item,code,size,price FROM cte2
    

    【讨论】:

    • 递归 CTE 可能非常昂贵 - 因为 OP 在 SQL Server 2012 上,所以我更喜欢他们可用的更有效的解决方案。
    • 好吧,如果没有正确实施并获取不必要的数据,它会很昂贵。但是是的,OP 适用于 SQL 2012,因此可以根据其性能使用新功能。不过我还没有比较性能。
    【解决方案4】:

    假设t 是您的表名:

    update t set price=p
    from (
      select nxt.item i,nxt.code c,nxt.size s,max(cur.price) p
      from t cur join t nxt 
      on (cur.item=nxt.item and cur.code=nxt.code 
       and cur.size<nxt.size and cur.price>nxt.price)
      group by nxt.item,nxt.code,nxt.size      
      ) a
    where item=i and code=c and size=s
    

    【讨论】:

    • 如果同一个 Item 和 Code 有多条 Size 较小的记录,这个查询会不会返回多条记录,因此无法更新?
    • @JonofAllTrades:你的意思是,例如,如果第 4 个价格更改为 477?
    • 但是cur 以较小的大小加入每条记录,每次都是nxt。我看不到您在哪里删除重复项。例如,如果 { OTH, 4 } 为 $0,则该表将自联接 4 到 3、4 到 2 和 4 到 1。
    • 你说得有道理,但我现在太累了……我改天再研究一下。
    • @JonofAllTrades:经过(半)良好的睡眠后,我设法让我的脑细胞按某种顺序排列并整理好。感谢大脑保险丝 :)
    猜你喜欢
    • 2021-10-28
    • 1970-01-01
    • 2021-01-14
    • 1970-01-01
    • 2016-11-11
    • 1970-01-01
    • 2015-06-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多