【问题标题】:Updating a column based on values in related rows根据相关行中的值更新列
【发布时间】:2012-05-21 15:11:00
【问题描述】:

我在 SQL Server 2008 中有如下表

  AMID                TierLevel
 --------            -------------
  999                 GOLD
  1000                SILVER   
  1000                GOLD
  1000                PLATINUM
  1000                BRONZE
  1001                GOLD
  1001                SILVER
  1002                SILVER
  1003                GOLD

现在我想像下面这样更新这个表

  AMID                TierLevel
 --------            -------------
  999                 GOLD
  1000               PLATINUM  
  1000               PLATINUM
  1000               PLATINUM
  1000               PLATINUM
  1001                GOLD
  1001                GOLD
  1002                SILVER
  1003                GOLD

这里是条件

  • 我希望同一个 AMID 具有唯一的 Tier 值,并且应该在优先级基础中选择 Tier 值,例如

    1. 白金
    2. 黄金
    3. 青铜
  • 这意味着如果它的等级值中存在最高的等级,则选择该等级。就像我在第二张表中显示的那样,白金代表 1000,黄金代表 1001..

请帮帮我

谢谢,
哈利

【问题讨论】:

    标签: sql sql-server-2008 sql-update rows


    【解决方案1】:
    DECLARE @amid TABLE (Amid INT, TierLevel VARCHAR(20));
    
    INSERT @amid VALUES
    (999 ,'GOLD'),
    (1000,'SILVER'), (1000,'GOLD'),   (1000,'PLATINUM'), (1000,'BRONZE'),
    (1001,'GOLD'),   (1001,'SILVER'),
    (1002,'SILVER'), (1003,'GOLD');
    
    ;WITH [priority](r, n) AS
    (
        SELECT 1, 'PLATINUM'
        UNION ALL SELECT 2, 'GOLD'
        UNION ALL SELECT 3, 'SILVER'
        UNION ALL SELECT 4, 'BRONZE'
    ),
    per_amid(amid, h) AS
    (
        SELECT a.amid, MIN(p.r)
          FROM @amid AS a
          INNER JOIN [priority] AS p
          ON a.TierLevel = p.n
          GROUP BY a.amid
    )
    UPDATE a
      SET TierLevel = p.n
      FROM @amid AS a
      INNER JOIN per_amid AS pa
      ON a.Amid = pa.amid
      INNER JOIN [priority] AS p
      ON pa.h = p.r
      -- added where clause to address question brought up on other answer
      WHERE a.TierLevel <> p.n;
    
    SELECT Amid, TierLevel FROM @amid;
    

    结果:

    Amid  TierLevel
    ----  ---------
    999   GOLD
    1000  PLATINUM
    1000  PLATINUM
    1000  PLATINUM
    1000  PLATINUM
    1001  GOLD
    1001  GOLD
    1002  SILVER
    1003  GOLD
    

    【讨论】:

    • @harry 那么你为什么接受它,然后不接受它,然后接受另一个正确的答案,因为我提供了帮助?
    • 哎哟..!对不起,伙计,我想我可以将这两个都标记为答案,首先我点击了你的,然后点击了另一个,可能它保留了第二个..我没有注意到它.. :(
    【解决方案2】:

    我会使用一个临时表来存储每个层的排名:

    DECLARE @Rank TABLE (ID INT NOT NULL PRIMARY KEY, Name VARCHAR(10) NOT NULL)
    INSERT @Rank VALUES (1, 'PLATINUM'), (2, 'GOLD'), (3, 'SILVER'), (4, 'BRONZE')
    
    ;WITH T AS
    (   SELECT  AMID, TierLevel, MIN(ID) OVER(PARTITION BY AMID) [MinID]
        FROM    #T
                INNER JOIN @Rank
                    ON Name = TierLevel
    )
    UPDATE  T
    SET     TierLevel = Name
    FROM    T
            INNER JOIN @Rank
                ON ID = MinID
    WHERE   TierLevel <> Name
    

    这是使用以下示例数据完成的:

    CREATE TABLE #T (AMID INT, TierLevel VARCHAR(10))
    INSERT #T VALUES 
        (999, 'GOLD'), 
        (1000, 'SILVER'), 
        (1000, 'GOLD'), 
        (1000, 'PLATINUM'), 
        (1000, 'BRONZE'),
        (1001, 'GOLD'),
        (1001, 'SILVER'),
        (1002, 'SILVER'),
        (1003, 'GOLD')
    

    【讨论】:

    • 谢谢 Gareth,这个正在为我的桌子工作 gr8,我想在这里问你一个小问题。这会更新表中的所有行还是只更新需要更改值的地方?因为它显示了从我的 200k 行表中更新的 190k 行..!!
    • 它会更新所有行,所以听起来有些行不是青铜、白银、黄金或白金!正如 Aaron 所建议的,我在 update 语句中添加了 where 子句。
    • @GarethD 不,我不认为“有些行不是青铜、白银、黄金或铂金”——没有 where 子句的更新语句根本不在乎,如果AMID 有 800 行都是银色的,它会将它们全部更新为银色,即使它们不应该成为更新的候选者,因为它们已经包含正确的值。
    • @AaronBertrand 确切地说,如果没有 where 子句 all 行,无论是否有必要都会更新。因此,如果表包含 200k 行,并且没有 where 子句,只有 190k 被更新,那么其他 10K 行发生了什么?这表明它们被INNER JOIN ON Name = TierLevel 排除在外,这意味着不是青铜、白银、黄金或铂金的AMID。这是我可以看到在没有 where 子句的情况下可以减少行数的唯一方法(请记住,直到关于更新的行数的评论之后,我才将其添加到答案中)。
    • 所以不是青铜、白银、黄金或白金......我意识到这是一个轻微的灰色区域,因为如果你要这样做 SELECT * FROM T WHERE AMID NOT IN ('Bronze', 'Silver', 'Gold', 'Platinum') 它不会返回这些缺失的行,但我只是在尝试解释 10k 行的差异。我想我应该更清楚。
    猜你喜欢
    • 2023-02-22
    • 1970-01-01
    • 2015-11-15
    • 1970-01-01
    • 2017-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多