2009-01-05 100 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; 

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

相關問題