2013-01-02 59 views
0

我想更新由唯一鍵標識的多行而不插入新行。使用唯一鍵更新多個行

下面是我的表:

CREATE TABLE `insert_update_ignore` (
    `obj_id` int(11) NOT NULL, 
    `obj_type` tinyint(4) NOT NULL, 
    `value` int(11) DEFAULT '-1', 
    UNIQUE KEY `unique_key` (`obj_id`,`obj_type`)) 
ENGINE=InnoDB DEFAULT CHARSET=utf8 

表有一些現有的記錄:

mysql> select * from insert_update_ignore; 
+--------+----------+-------+ 
| obj_id | obj_type | value | 
+--------+----------+-------+ 
|  1 |  1 | -1 | 
|  1 |  2 | -1 | 
|  2 |  1 | -1 | 
|  2 |  2 | -1 | 
+--------+----------+-------+ 

我有一些值更新表中的列value

INSERT INTO insert_update_ignore(obj_id, obj_type, value) 
    VALUES(1, 1, 1), 
      (1, 2, 3), 
      (2, 1, 1), 
      (2, 2, 5), 
      (3, 1, 10) 
    ON DUPLICATE KEY UPDATE 
     value = VALUES(value); 

除了最後一個值,即(3,1,10)被插入表格之外,這幾乎完成了工作。這個不應該被插入,因爲唯一的鍵(3,1)以前不存在。

我該怎麼做UPDATE部分,而不是INSERT?如果 存在更好的實現,則可以更改表架構。要更新的值是從其他數據庫(運行在不同的機器和不同端口上)計算得出的。

我挖出下面的一個做這項工作,但是如果這個值是幾千,那麼這個陳述就太大了。任何更優雅的方式來做到這一點?謝謝,如果任何人可以幫助這一點。 P.S我在Python中編寫這個代碼並使用MySQLdb庫。

UPDATE insert_update_ignore 
SET value = CASE 
    WHEN (obj_id = 1 AND obj_type = 1) THEN 1 
    WHEN (obj_id = 1 AND obj_type = 2) THEN 3 
    WHEN (obj_id = 2 AND obj_type = 1) THEN 1 
    WHEN (obj_id = 2 AND obj_type = 2) THEN 5 
    WHEN (obj_id = 3 AND obj_type = 1) THEN 10 
    ELSE value 
END 
WHERE (obj_id, obj_type) IN ((1, 1), (1,2), (2, 1), (2, 2), (3, 1)); 

回答

0

INSERT整個目的是要插入新行,所以當然這將插入新行(如果重複的鍵沒有找到,否則就對其進行更新)。如果您只想更新現有行,請使用UPDATE查詢。

而不是使用CASE ... WHEN ... THEN ... ELSE ... END迭代每個唯一密鑰和UPDATE ... WHERE ...

編輯:

例如:

UPDATE `insert_update_ignore` SET `value` = 1 WHERE `obj_id` = 1 AND `obj_type` = 1; 
UPDATE `insert_update_ignore` SET `value` = 3 WHERE `obj_id` = 1 AND `obj_type` = 2; 
UPDATE `insert_update_ignore` SET `value` = 1 WHERE `obj_id` = 2 AND `obj_type` = 1; 
UPDATE `insert_update_ignore` SET `value` = 5 WHERE `obj_id` = 2 AND `obj_type` = 2; 
UPDATE `insert_update_ignore` SET `value` = 10 WHERE `obj_id` = 3 AND `obj_type` = 1; 

前4個查詢將更新匹配WHERE子句中的標準,其中的行而最後不會因爲沒有行滿足條件。

+0

請讓我看看'UPDATE' SQL?我很困惑。 – schemacs

+0

已被加入到答案。 – MichaelRushton

+0

如果找不到更好的替代方法,我將使用'cursor.executemany'來完成這項工作。謝謝。 – schemacs

1

您可以先將所有希望更新的值放入臨時表中。 然後,如果可以連接,請從臨時表中更新原始表中的所有值。

create temporary table temp like insert_update_ignore; 

insert into temp 
    values(1, 1, 1), 
      (1, 2, 3), 
      (2, 1, 1), 
      (2, 2, 5), 
      (3, 1, 10); 

update insert_update_ignore i 
join temp t 
using (obj_id, obj_type) 
set i.value = t.value; 

drop temporary table temp; 

我已經把所有這些都寫入了SQLFiddle