2014-09-03 53 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