代码之家  ›  专栏  ›  技术社区  ›  Paulius

是否可以使用一个update sql语句执行多个更新?

  •  27
  • Paulius  · 技术社区  · 16 年前

    假设我有一张桌子 TBL 带柱 身份证件 标题 . 我需要更改标题栏的所有值:

    1. 从“A-1”到“A1”,
    2. 从“A.1”到“A1”,
    3. 从“B-1”到“B1”,
    4. 从“B.1”到“B1”。

    现在,我正在执行两个更新语句:

    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 回复  |  直到 16 年前
        1
  •  22
  •   Jonathan Leffler    16 年前

    在更一般的情况下,可能有数百个映射到每个新值,您将创建一个新值和旧值的单独表,然后在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);
    

    这两个select语句都至关重要。第一个是一个相关的子查询(不一定很快,但如果映射器表有数千行,则比大多数替代查询都快),它从对应于旧值的映射表中提取新值。第二种方法确保只修改映射表中具有值的行;这一点非常重要,否则,对于没有映射项的行(以及在开始之前正常的记录),标题将设置为空。

    对于一些备选方案,案例操作是可以的。但是,如果要执行成百上千或数以百万计的映射,那么很可能会超出DBMS中SQL语句长度的限制。

        2
  •  23
  •   casperOne    16 年前

    您可以使用一个语句和多个case语句

    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')
    

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

        3
  •  9
  •   mrdenny    16 年前

    认真研究乔纳森的回答。

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

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

        4
  •  3
  •   Matt Hamilton    16 年前

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

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

    你想要那样的东西吗?

        5
  •  0
  •   Charles Bretana    16 年前

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