【问题标题】:Do I need a where clause in a conditional UPDATE?我是否需要条件更新中的 where 子句?
【发布时间】:2020-05-30 04:55:29
【问题描述】:

我们从另一个表中导入了大量数据。现在我正在尝试纠正其中的一些问题。

UPDATE [x10ddata].[dbo].[ResourceTest]
  SET [Country] = (CASE
      WHEN [Country] IN ('Aezerbaijan', 'AZERBIJAN') THEN 'Azerbaijan'
      WHEN [Country] = 'Belgique'    THEN 'Belgium'
      WHEN [Country] = 'China (RPC)' THEN 'China'
      WHEN [Country] = 'Columbia'    THEN 'Colombia'
     WHEN [Country] = 'Croatia (Local Name: Hrvatska)' THEN 'Croatia'
     .....//...
     WHEN [Country] IN ('U.S.', 'U.S.A', 'U.S.A.', 'US', 'USA', 
                         'USA - Maryland', 'USAQ') THEN 'United States'
    END)   
  GO

我没有使用 ELSE,因为很多行都有有效的国家/地区。我的问题是知道我是否需要 WHERE 子句来过滤将受到影响的行?

我问这个问题的原因是,我选择了一个测试表并尝试了脚本。根据输出,所有行都受到影响,但是当我仔细检查时,并非所有行都受到影响。很混乱。

感谢您的帮助

【问题讨论】:

  • 如果你想在所有行上运行更正代码,那么没有。
  • 对于CASE 语句未达到指定条件之一的任何记录,NULLCASE 返回的内容,因此在这些情况下将 Country 设置为 NULL .
  • 现在“有一个有效国家”的行是什么? NULL?只需将ELSE [Country] 包含在内,即可快速解决低效问题。
  • 如果您可以正确规范您的数据,您甚至根本不需要此更新。将国家/地区名称存储在表格中,这很好地表明标准化在这里更合适。

标签: sql sql-server tsql


【解决方案1】:

如果没有满足 when 子句,case 语句将返回 null。您可以使用这个简单的 sql 来验证这一点:

declare @i int
set @i = 2
select case when @i = 1 then 'A' end AS Column1

这将返回null,因为@i 不是1

要在您的情况下解决此问题,您可以像您所说的那样添加 where 子句,或者更简单的选项可能是在所有 WHEN 子句之后添加 ELSE [Country]。这意味着“如果我不需要更改国家/地区字段,则只需使用与之前相同的值即可。”

【讨论】:

    【解决方案2】:

    您不需要 WHERE 子句,但需要 ELSE 子句。将您的声明更改为:

    UPDATE [x10ddata].[dbo].[ResourceTest]
      SET [Country] = (CASE
          WHEN [Country] IN ('Aezerbaijan', 'AZERBIJAN') THEN 'Azerbaijan'
          WHEN [Country] = 'Belgique'    THEN 'Belgium'
          WHEN [Country] = 'China (RPC)' THEN 'China'
          WHEN [Country] = 'Columbia'    THEN 'Colombia'
         WHEN [Country] = 'Croatia (Local Name: Hrvatska)' THEN 'Croatia'
         .....//...
         WHEN [Country] IN ('U.S.', 'U.S.A', 'U.S.A.', 'US', 'USA', 
                             'USA - Maryland', 'USAQ') THEN 'United States'
         ELSE [Country]
        END)
    

    【讨论】:

    • 虽然可行,但将行更新为相同的值似乎是错误的。
    • @Jodrell - 另一种方法是省略 ELSE 子句,在这种情况下,与 WHEN 子句中的任何国家/地区名称不匹配的所有行都将其 [Country] 列设置为 NULL .另一种选择是添加一个重新声明国家名称的 WHERE 子句,但是如果缺少国家名称、键入错误等,这会增加出错的可能性。我认为使用没有 WHERE 子句的 CASE 表达式是一个合理的选择。 YMMV。
    【解决方案3】:

    或者,

    制作换算表,

    DECLARE @conversion TABLE
    (
        [Before] NVARCHAR(250) NOT NULL,
        [After] NVARCHAR(250) NOT NULL
    );
    
    INSERT @conversion
    VALUES
    ('Aezerbaijan', 'Azerbaijan'),
    ...
    ('USAQ', 'United States');
    

    那就做吧

    UPDATE [x10ddata].[dbo].[ResourceTest]
                SET [Country] = [C].[After]
        FROM
                [x10ddata].[dbo].[ResourceTest]
            JOIN
                @conversion [C]
                    ON [C].[Before] = [C].[Country];
    

    与扩展 CASE 方法相比,这具有许多潜在的性能优势,其中仅影响需要更改的行。

    使用临时表而不是表变量并在 [Before] 上创建索引以优化连接可能值得。

    【讨论】:

      【解决方案4】:

      不,您不需要 where 子句,因为您的 CASE 语句包含您的逻辑。

      注意:如果某个值与您的任何 CASE 语句都不匹配,那么它将返回 null。所以我建议在最后添加 ELSE [Country]。这是一个演示我在说什么的例子

      SELECT * INTO #yourTable
      FROM
      (
          SELECT 1 ID, CAST('OldValue' AS VARCHAR(25)) val
          UNION ALL
          SELECT 2 , 'OldValue'
          UNION ALL
          SELECT 3,'Doesnt need to be updated'
      ) A
      
      SELECT *
      FROM #yourTable;
      

      结果:

      ID          val
      ----------- -------------------------
      1           OldValue
      2           OldValue
      3           Doesnt need to be updated
      

      现在更新:

      UPDATE #yourTable
      SET val = 
          CASE 
              WHEN ID = 1 THEN 'NewValue1'
              WHEN ID = 2 THEN 'NewValue2'
              --Add this so you leave values alone if they don't match your case statements
              ELSE val
          END
      FROM #yourTable
      
      
      SELECT *
      FROM #yourTable
      

      结果:

      ID          val
      ----------- -------------------------
      1           NewValue1
      2           NewValue2
      3           Doesnt need to be updated
      

      【讨论】:

        【解决方案5】:

        不,你不需要它。除了通过额外(不必要的)磁盘写入和锁定(阻塞其他会话)可能导致的性能成本之外,物理结果将是相同的。

        有人可能会争辩说,您应该使用 WHERE 子句,不仅是出于性能原因,而且是为了更好地捕捉和传达意图。

        【讨论】:

          猜你喜欢
          • 2016-06-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-08-10
          • 2014-09-25
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多