2009-01-05 46 views
24

假设我有一个表tblID标题。 我需要改变标题列的所有值:是否可以使用单个UPDATE SQL语句执行多个更新?

  1. 从 'A1' 到 'A1',
  2. 从 'A.1' 到 'A1',
  3. 从“B-1 '到'b1',
  4. 从'b.1'到'b1'。

现在,我正在执行两个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秒内完成),并且我有大量的更新来执行。

那么,是否有可能合并更新,因此它只会扫描一次表?或者也许,在这种情况下有更好的方法来处理。

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

+0

因此,从你的编辑评论推断,字符串本身可以是不同的,但你尝试的更新是否遵循一种模式?如果是这样,那是什么?如果什么都没有模式,那么没有解决方案,你必须单独编码每个独特的更新 – 2009-01-05 14:51:14

+0

我有一个*正确*值的列表,并且我有一个明确指定的错误*值列表(以及哪个错误的值必须是改成正确的值)。所以是的 - 更新确实有一个模式。简而言之 - 每次更新都会更改一个值,但前提是旧值在指定的值列表中。 – Paulius 2009-01-06 15:37:04

回答

19

在更一般的情况下,其中可能有数百映射到每个新的价值观,你会创建新的旧的和值的一个单独的表,然后使用在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语句都是至关重要的。第一个是相关的子查询(不一定是快速的,但如果映射表具有数千行,则比大多数替代方案更快)将新值从对应于旧值的映射表中提取出来。第二个确保只修改映射表中具有值的那些行;这是至关重要的,否则,对于没有映射条目的那些行,标题将被设置为空(并且这些是在你开始之前确定的那些记录)。

对于一些替代方案,CASE操作是可以的。但是,如果您有数百或数千或数百万个映射要执行,那么您可能会超出数据库管理系统中SQL语句长度的限制。

3

如果转换是因为你的例子一样简单,你可以做更新字符串操作的一点点:

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

会像你的工作?

+0

不,不幸的是,我处理的真实I数据并不像我的例子那么简单。这对我不起作用。不过谢谢你。 – Paulius 2009-01-05 02:12:10

+0

听起来像casperOne使用CASE WHEN表达式是当时的出路。 – 2009-01-05 02:14:09

21

您可以使用一个语句和若干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') 

这将减少写入表的次数。

0

或者

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

正如我在Matt的回答中所提到的那样 - 数据在真实数据库中并不那么简单。 – Paulius 2009-01-05 02:17:15

8

努力解决乔纳森的答案。

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

他的初始版本将需要大量的读取映射器表。

相关问题