将INSERT语句自动转换为UPDATE的简单方法?

时间:2010-10-27 15:48:00

标签: mysql mysqldump

我想使用mysqldump的输出来更新实时数据库中的条目。我不想先删除条目,简单的更新语句都没问题。有没有一种简单的方法将包含INSERT语句的mysqldump的输出转换为相应的UPDATE语句?

这似乎是一个基本功能,所以我确信有人创建了一个工具或想出了一种方法来快速完成它,所以人们不必每次都为自己编写脚本来重新发明轮子此

编辑:我正在寻找一个通用的解决方案,而不是我必须手动枚举实际表列的方法。这是一个普遍的问题,所以我认为应该有一个独立于表的解决方案。

5 个答案:

答案 0 :(得分:8)

您可以将mysqldump数据恢复到新的临时数据库,然后使用多表UPDATE语法进行更新。

UPDATE mydb.mytable AS dest JOIN tempdb.mytable AS origin USING (prim_key)
SET dest.col1 = origin.col1,
    dest.col2 = origin.col2,
    ...

然后删除临时数据库。

答案 1 :(得分:4)

这是添加ON DUPLICATE KEY UPDATE子句

的问题

http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html

答案 2 :(得分:4)

Mchl的答案是有效的另一个简单的解决方法是将'INSERT'更改为'REPLACE'。两者都需要简单的搜索/替换操作(我使用sed)。但如果定期运行,那么它将是复制/使用时间戳创建包含已修改/新记录的的加载程序文件的理想选择。

mysldump也有一个--replace选项,因此可以省略sed步骤。

答案 3 :(得分:0)

我一直在寻找解决方案,我认为这是一个常见的问题,但我们找不到一个问题。看起来好像是在mysqldump中,但是基于MySQL板上的这个功能请求,它不是:

https://bugs.mysql.com/bug.php?id=73190

下面的转录:

[3 Jul 2014 21:23] Christopher Schultz
Description:
mysqldump currently supports two different options for dealing with PK collisions:

  --insert-ignore (uses INSERT IGNORE)
  --replace       (uses REPLACE INTO instead of INSERT INTO)

I'd like to request an additional option that uses INSERT ... ON DUPLICATE KEY UPDATE ... when used.

This will allow one database to be used as a source to update another database without the following problems:

Using INSERT IGNORE will ignore any updates to existing rows that are coming from the file being loaded "on top of" an existing database.

Using REPLACE ends up churning the primary index, failing when foreign keys point to the record being updated (REPLACED), or ON DELETE CASCADE wiping-out records in other tables as the records in the target table are "updated" (using REPLACE).

There are two significant downsides to using ON DUPLICATE KEY UPDATE, of course:

1. The dump file will get much bigger, because the bulk-loading syntax for INSERT can no longer be used.
2. The dump file will get much longer, because ON DUPLICATE KEY UPDATE requires that all values be specified twice: once in the VALUES() section and then a second time in the field=value, field=value part after "ON DUPLICATE KEY UPDATE" phrase.

Bug 11422 [http://bugs.mysql.com/bug.php?id=11422] requests the ability to simply say "ON DUPLICATE KEY UPDATE" and allow the engine to use the VALUES to update all fields in the table. Fixing bug 11422 and using the solution here would mitigate both downsides because then extended syntax could (possibly?) be used and the values would not have to be mentioned twice in the dump file.

I have found many posts online about how to do something like this and the responses always steer the person toward --insert-ignore or --replace but there are many scenarios where the above request would be preferable.

How to repeat:
(This is a feature request)
[17 Jul 2015 14:23] Georgi Kodinov
Thank you for the reasonable feature request.

答案 4 :(得分:0)

我不敢相信没有人创建了一个简单的工具来将一组INSERT行转换为一组UPDATE命令。所以我做了我自己的。您可以在有输入和输出文本框的this fiddle中对其进行测试。

警告!这不是万无一失的,有很多假设。例如,如果您的值中包含逗号,它可能会失败。

我还假定第一个字段是唯一键

function substrBetween(str,before,after){
    var arr = str.split(before);
    arr.shift();
    str = arr.join(before);
    arr = str.split(after);
    str = arr.shift();
    return str;
}

var insertQuery = $('#query').val();

var lines = insertQuery.split('\n');
var header = lines[0];
var tableName = substrBetween(header,"INTO `","`");
var varNames = substrBetween(header,"(`","`)").split("`, `");

var out = "";
for (i=1; i<lines.length; i++){
  var line = lines[i];
  if (line[line.length -1] == ";"){
    line = line.slice(0, -1) + ',';
  }
  var values = substrBetween(line,"(","),").split(", ");
  out += "UPDATE `"+tableName+"` SET ";
  for (j=1; j<values.length; j++){
    out += "`"+varNames[j]+"`="+values[j]+", ";
  }
  out = out.slice(0, out.length-2);
  out += " WHERE `"+varNames[0]+"`="+values[0]+";\n";
}
return out;

示例输入:

INSERT INTO `devices` (`name`, `idGroup1`, `idGroup2`, `label`) VALUES
('3703-001', 16, 5, 'Meter BB #1'),
('3703-002', 12, 8, 'Meter CC #2'),
('3703-003', 12, 0, 'Meter #3'),
('3703-004', 12, 24, 'Meter building F');

对应的输出:

UPDATE `devices` SET `idGroup1`=16, `idGroup2`=5, `label`='Meter BB #1' WHERE `name`='3703-001';
UPDATE `devices` SET `idGroup1`=12, `idGroup2`=8, `label`='Meter CC #2' WHERE `name`='3703-002';
UPDATE `devices` SET `idGroup1`=12, `idGroup2`=0, `label`='Meter #3' WHERE `name`='3703-003';
UPDATE `devices` SET `idGroup1`=12, `idGroup2`=24, `label`='Meter building F' WHERE `name`='3703-004';