2014-09-03 93 views
1

我按行做一個錶行的更新:如何從值列表更新值的列一組記錄

UPDATE table 
SET col = $value 
WHERE id = $id 

現在,如果我更新例如每個記錄10000條記錄獲得$value,但哪個$id獲得哪個$value並不重要。我唯一的要求是,我正在更新的所有記錄都以$value結尾。
所以我怎麼會這個更新轉換爲類似

UPDATE table 
SET col ?????? what here from a $value_list??? 
WHERE id IN ($id_list) 

即通過列表ID和不知何故的價值觀和ids的範圍得到A

回答

1

讓我們假設你有兩個逗號分隔的列表你的ID和你的值與相同的項目數。然後,你可以做你的更新像那些語句:

-- the list of the ids 
SET @ids = '2,4,5,6'; 
-- the list of the values 
SET @vals = '17, 73,55, 12'; 

UPDATE yourtable 
INNER JOIN (
    SELECT 
     SUBSTRING_INDEX(SUBSTRING_INDEX(t.ids, ',', n.n), ',', -1) id, 
     SUBSTRING_INDEX(SUBSTRING_INDEX(t.vals, ',', n.n), ',', -1) val 
    FROM (SELECT @ids as ids, @vals as vals) t 
    CROSS JOIN (
     -- build for up to 1000 separated values 
     SELECT 
      1 + a.N + b.N * 10 + c.N * 100 AS n 
     FROM 
      (SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a 
      ,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b 
      ,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) c 
     ORDER BY n 
    ) n 
    WHERE n <= (1 + LENGTH(t.ids) - LENGTH(REPLACE(t.ids, ',', ''))) 
) t1 
ON 
    yourtable.id = t1.id 
SET 
    yourtable.val = t1.val; 

說明

內一系列工會建立從1到1000的數字表,您應該能夠擴大這一機制您的需求:

-- build for up to 1000 separated values 
SELECT 
    a.N + b.N * 10 + c.N * 100 + 1 AS n 
FROM 
    (SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) a 
    ,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) b 
    ,(SELECT 0 AS N UNION ALL SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 UNION ALL SELECT 4 UNION ALL SELECT 5 UNION ALL SELECT 6 UNION ALL SELECT 7 UNION ALL SELECT 8 UNION ALL SELECT 9) c 
ORDER BY n 

我們用這個數字來獲取項目從我們的名單與嵌套調用SUBSTRING_INDEX

SUBSTRING_INDEX(SUBSTRING_INDEX(t.ids, ',', n.n), ',', -1) id, 
SUBSTRING_INDEX(SUBSTRING_INDEX(t.vals, ',', n.n), ',', -1) val 

WHERE子句獲得的項目數量(只確定了兩個中的一個)列表:

WHERE n <= (1 + LENGTH(t.ids) - LENGTH(REPLACE(t.ids, ',', ''))) 

因爲我們已經得到了分離器的一個occurence少,我們加1的區別帶有分隔符的列表的長度和沒有出現分隔符的所有列表的長度。

然後我們使用JOIN操作對外部UPDATE語句中的id值執行UPDATE。

看來它的工作this fiddle

相信我:這比痛苦的逐行更新要快得多。

+0

但我一次只有10.000個ID和值。我可以像使用這麼多值一樣使用sql變量嗎? – Jim 2014-09-04 07:01:10

+0

您可以達到[最大允許數據包](http://dev.mysql.com/doc/refman/5.5/en/packet-too-large.html)限制。這主要取決於你的價值觀的大小。如果值是例如字符串,那麼列表的分隔符也可能不包含在這些列表中。如果你接近這個限制,你可以分批處理1000個。所以你會大大限制查詢的數量。 – VMai 2014-09-04 07:07:01

+0

+ 1.我需要仔細研究這個答案,以充分理解它。一個問題。這比使用'CASE id WHEN 1 then val1 etc'更高效,並且通過字符串concats在應用程序中構造這個查詢? – Jim 2014-09-04 07:23:53