是否可以使用单个UPDATE SQL语句执行多个更新?

时间:2009-01-05 01:59:07

标签: sql sql-server sql-server-2005 tsql optimization

假设我有一个表 tbl ,其中列 id title 。 我需要更改title列的所有值:

  1. 从'a-1'到'a1',
  2. 从'a.1'到'a1',
  3. 从'b-1'到'b1',
  4. 从'b.1'到'b1'。
  5. 现在,我正在执行两个UPDATE语句:

    UPDATE tbl SET title='a1' WHERE title IN ('a-1', 'a.1')
    UPDATE tbl SET title='b1' WHERE title IN ('b-1', 'b.1')
    

    如果表很小,并且单个语句在不到一秒的时间内完成,并且您只需要执行一些语句,那么这根本不是问题。

    你可能已经猜到了 - 我有一个巨大的表来处理(一个语句在大约90秒内完成),我有大量的更新要执行。

    那么,是否可以合并更新,以便只扫描一次表?或许,在这样的情况下,有更好的方法来处理。

    编辑:注意,我正在使用的真实数据和我必须执行的数据更改实际上并不那么简单 - 字符串更长并且它们不遵循任何模式(它是用户数据,所以不能做任何假设 - 它可以是任何东西。)

5 个答案:

答案 0 :(得分:23)

您可以使用一个陈述和多个案例陈述

update tbl
  set title = 
    case
      when title in ('a-1', 'a.1') then 'a1'
      when title in ('b-1', 'b.1') then 'b1'
      else title
    end

当然,这会导致对每条记录进行写入,而对于索引,这可能是一个问题,因此您只能过滤掉要更改的行:

update tbl
  set title = 
    case
      when title in ('a-1', 'a.1') then 'a1'
      when title in ('b-1', 'b.1') then 'b1'
      else title
    end
where
  title in ('a.1', 'b.1', 'a-1', 'b-1')

这将减少对表的写入次数。

答案 1 :(得分:22)

在更一般的情况下,每个新值可能有数百个映射,您可以创建一个旧值和新值的单独表,然后在UPDATE语句中使用它。在SQL的一种方言中:

CREATE TEMP TABLE mapper (old_val CHAR(5) NOT NULL, new_val CHAR(5) NOT NULL);
...multiple inserts into mapper...
INSERT INTO mapper(old_val, new_val) VALUES('a.1', 'a1');
INSERT INTO mapper(old_val, new_val) VALUES('a-1', 'a1');
INSERT INTO mapper(old_val, new_val) VALUES('b.1', 'b1');
INSERT INTO mapper(old_val, new_val) VALUES('b-1', 'b1');
...etcetera...

UPDATE tbl
   SET title = (SELECT new_val FROM mapper WHERE old_val = tbl.title)
   WHERE title IN (SELECT old_val FROM mapper);

两个选择陈述都至关重要。第一个是相关的子查询(不一定快,但如果映射器表有数千行,则比大多数备选方案更快)将新值拉出对应于旧值的映射表。第二个确保仅修改映射表中具有值的那些行;这是至关重要的,否则,对于那些没有映射条目的行,标题将被设置为null(这些是你开始之前没有的记录)。

对于一些替代方案,CASE操作没问题。但是,如果要执行数百或数千或数百万个映射,那么您可能会超出DBMS中SQL语句长度的限制。

答案 2 :(得分:9)

解决乔纳森的回答。

UPDATE tbl
   SET title = new_val
FROM mapper
WHERE title IN (SELECT old_val FROM mapper)
     AND mapper.old_val = tbl.title;

他的初始版本需要对mapper表进行大量读取。

答案 3 :(得分:3)

如果转换和示例一样简单,您可以通过一些字符串操作来进行更新:

UPDATE tbl 
SET title = left(title, 1) + right(title, 1) 
WHERE title IN ('a-1', 'a.1', 'b-1', 'b.1')

这样的事情对你有用吗?

答案 4 :(得分:0)

   Update Table set 
     title = Replace(Replace(title, '.', ''), '-', '')
   Where title Like '[ab][.-]1'