我知道你可以插入多行一次,是否有一个方法更新多个行一次(在,在一个查询)在MySQL?

编辑:例如,我有以下

Name   id  Col1  Col2
Row1   1    6     1
Row2   2    2     3
Row3   3    9     5
Row4   4    16    8

我想要结合以下所有更新一次查询

UPDATE table SET Col1 = 1 WHERE id = 1;
UPDATE table SET Col1 = 2 WHERE id = 2;
UPDATE table SET Col2 = 3 WHERE id = 3;
UPDATE table SET Col1 = 10 WHERE id = 4;
UPDATE table SET Col2 = 12 WHERE id = 4;
有帮助吗?

解决方案

是的,这是可能的-你可以用刀...关于重复的关键的更新。

用你的例子:

INSERT INTO table (id,Col1,Col2) VALUES (1,1,1),(2,2,3),(3,9,3),(4,10,12)
ON DUPLICATE KEY UPDATE Col1=VALUES(Col1),Col2=VALUES(Col2);

其他提示

由于你具有动态的价值,需要使用一个或如果情况列于以更新。它变得有点丑,但它应的工作。

用你的实例,你可以做到这一点,如:

UPDATE table SET Col1 = CASE id 
                          WHEN 1 THEN 1 
                          WHEN 2 THEN 2 
                          WHEN 4 THEN 10 
                          ELSE Col1 
                        END, 
                 Col2 = CASE id 
                          WHEN 3 THEN 3 
                          WHEN 4 THEN 12 
                          ELSE Col2 
                        END
             WHERE id IN (1, 2, 3, 4);

问题是旧的,但我想扩展的主题与另一个答案。

我的意思是,最简单的方法来实现它只是包裹多个查询有交易。所接受的答案 INSERT ... ON DUPLICATE KEY UPDATE 是一个漂亮的劈,但是应该意识到的缺点和限制:

  • 如前所述,如果发生在启动查询与行其主要的钥匙也不存在表,查询插入新的"成熟"的记录。可能这是不是你想要的
  • 如果你有一个表与非空领域,而不默认值和不想摸摸这个领域中的查询,你会得到 "Field 'fieldname' doesn't have a default value" MySQL警告,甚至如果你不要插入一个单一的行在所有。它会让你陷入麻烦,如果你决定要严格和转mysql警告,进入运行时的例外情况在应用程序。

我做了一些性能测试用于三个建议的变体,包括 INSERT ... ON DUPLICATE KEY UPDATE 变型,一个变体"的情况下/当然"条款和一个天真的做法与交易。你可能会得到代码和结果 在这里,.总的结论是,该变式与情况的声明证明是快两倍,其他两个变体,但这是相当难以编写正确和注射安全代码的,所以我个人坚持的最简单的方法:使用的交易。

编辑: 调查结果 Dakusan 证明我的能估计是不是很有效的。请看看 这个答案 对于另一个,更加详细的研究。

不知道为什么另一个有益的选择是没有提及:

UPDATE my_table m
JOIN (
    SELECT 1 as id, 10 as _col1, 20 as _col2
    UNION ALL
    SELECT 2, 5, 10
    UNION ALL
    SELECT 3, 15, 30
) vals ON m.id = vals.id
SET col1 = _col1, col2 = _col2;

所有如下适用于少.

我觉得我知道的速度的3个不同的方法是重要的。

有3个方法:

  1. 插入:插入与上重复的关键的更新
  2. 交易:在哪里你做一个更新的每个内记录的交易
  3. 情况:在其中一个情况下,当为每个不同的记录内更新

我只是测试这个,插入的方法是 6.7x 更快的我比交易的方法。我试过在一套既3 000至30 000名行。

交易的方法仍然具有运行每一个独特的查询,这需要时间,虽然它批次的结果在存储器,或什么东西,同时执行。交易的方法也是相当昂贵的,在这两个复制和查询的日志。

甚至更糟糕的是,这种情况的方法是 41.1x 慢于插入的方法w/30 000名录(6.1x慢于交易)。和 75x 慢些.插入和情况的方法打破了甚至在-1 000个记录。甚至在100记录的情况下,方法是勉强的速度更快。

因此,在一般情况下,我感觉插入的方法是最好和最容易使用。查询更小的和更容易阅读并且仅占1询的行动。这适用于少和一些.

奖励的东西:

该解决方案插入非默认的领域的问题是暂时关闭相关的SQL模式: SET SESSION sql_mode=REPLACE(REPLACE(@@SESSION.sql_mode,"STRICT_TRANS_TA‌​BLES",""),"STRICT_AL‌​L_TABLES","").确保保存 sql_mode 第一如果你计划在恢复它。

至于其他意见,我已经看到说auto_increment去使用的方法插入的,我试过,而且似乎不是这种情况。

代码运行的测试如下。它还产出。SQL的文件中删除php解释开销

<?
//Variables
$NumRows=30000;

//These 2 functions need to be filled in
function InitSQL()
{

}
function RunSQLQuery($Q)
{

}

//Run the 3 tests
InitSQL();
for($i=0;$i<3;$i++)
    RunTest($i, $NumRows);

function RunTest($TestNum, $NumRows)
{
    $TheQueries=Array();
    $DoQuery=function($Query) use (&$TheQueries)
    {
        RunSQLQuery($Query);
        $TheQueries[]=$Query;
    };

    $TableName='Test';
    $DoQuery('DROP TABLE IF EXISTS '.$TableName);
    $DoQuery('CREATE TABLE '.$TableName.' (i1 int NOT NULL AUTO_INCREMENT, i2 int NOT NULL, primary key (i1)) ENGINE=InnoDB');
    $DoQuery('INSERT INTO '.$TableName.' (i2) VALUES ('.implode('), (', range(2, $NumRows+1)).')');

    if($TestNum==0)
    {
        $TestName='Transaction';
        $Start=microtime(true);
        $DoQuery('START TRANSACTION');
        for($i=1;$i<=$NumRows;$i++)
            $DoQuery('UPDATE '.$TableName.' SET i2='.(($i+5)*1000).' WHERE i1='.$i);
        $DoQuery('COMMIT');
    }

    if($TestNum==1)
    {
        $TestName='Insert';
        $Query=Array();
        for($i=1;$i<=$NumRows;$i++)
            $Query[]=sprintf("(%d,%d)", $i, (($i+5)*1000));
        $Start=microtime(true);
        $DoQuery('INSERT INTO '.$TableName.' VALUES '.implode(', ', $Query).' ON DUPLICATE KEY UPDATE i2=VALUES(i2)');
    }

    if($TestNum==2)
    {
        $TestName='Case';
        $Query=Array();
        for($i=1;$i<=$NumRows;$i++)
            $Query[]=sprintf('WHEN %d THEN %d', $i, (($i+5)*1000));
        $Start=microtime(true);
        $DoQuery("UPDATE $TableName SET i2=CASE i1\n".implode("\n", $Query)."\nEND\nWHERE i1 IN (".implode(',', range(1, $NumRows)).')');
    }

    print "$TestName: ".(microtime(true)-$Start)."<br>\n";

    file_put_contents("./$TestName.sql", implode(";\n", $TheQueries).';');
}
UPDATE table1, table2 SET table1.col1='value', table2.col1='value' WHERE table1.col3='567' AND table2.col6='567'

这应该作用于你。

有一个参考 MySQL手册 对多个表格。

使用临时表格

// Reorder items
function update_items_tempdb(&$items)
{
    shuffle($items);
    $table_name = uniqid('tmp_test_');
    $sql = "CREATE TEMPORARY TABLE `$table_name` ("
        ."  `id` int(10) unsigned NOT NULL AUTO_INCREMENT"
        .", `position` int(10) unsigned NOT NULL"
        .", PRIMARY KEY (`id`)"
        .") ENGINE = MEMORY";
    query($sql);
    $i = 0;
    $sql = '';
    foreach ($items as &$item)
    {
        $item->position = $i++;
        $sql .= ($sql ? ', ' : '')."({$item->id}, {$item->position})";
    }
    if ($sql)
    {
        query("INSERT INTO `$table_name` (id, position) VALUES $sql");
        $sql = "UPDATE `test`, `$table_name` SET `test`.position = `$table_name`.position"
            ." WHERE `$table_name`.id = `test`.id";
        query($sql);
    }
    query("DROP TABLE `$table_name`");
}

你可以的别名的同样的表给你的id是你想要插入(如果正在执行由行更新:

UPDATE table1 tab1, table1 tab2 -- alias references the same table
SET 
col1 = 1
,col2 = 2
. . . 
WHERE 
tab1.id = tab2.id;

此外,它应该似乎是显而易见的,你还可以更新,从其他表格。在这种情况下,更新双作为一个"选择"的声明,在给你的数据表的指定.你是明确说明在您的查询,更新值,因此,第二表不受影响。

为什么没有人说 多个发言中的一种查询?

在php中,你使用 multi_query 方法)的预的实例。

php手册

MySQL可选允许有多个发言,在发言一串。发送多发言一次,减少了客户机-服务器往返行程,但需要特殊处理。

这里是结果进行比较的其他3种方法在更新30,000原料。代码可以被发现 在这里, 这是基于答复@Dakusan

交易:5.5194580554962
插入:0.20669293403625
情况:16.474853992462
多:0.0412278175354

正如你可以看到,多个语句的查询是更有效率比最高的答案。

如果你得到错误信息是这样的:

PHP Warning:  Error while sending SET_OPTION packet

你可能需要增加 max_allowed_packet 在mysql配置文件,该文件在我的机器 /etc/mysql/my.cnf 然后重新启动该.

你也可能有兴趣使用联接在更新,这是可能的。

Update someTable Set someValue = 4 From someTable s Inner Join anotherTable a on s.id = a.id Where a.id = 4
-- Only updates someValue in someTable who has a foreign key on anotherTable with a value of 4.

编辑:如果你正在更新并不是来自别处的数据库,则需要问题个更新的查询。

有一个设定你可以改变所谓的'多声明',禁止MySQL'安全机构'实施,以防止(多个)注射命令。典型的要MySQL'辉煌的执行情况,它还可以防止用户从事有效的查询。

在这里(http://dev.mysql.com/doc/refman/5.1/en/mysql-set-server-option.html)是一些信息在C执行设定。

如果你使用PHP,可以使用)的预做多发言(我认为php有附带)的预,而现在)

$con = new mysqli('localhost','user1','password','my_database');
$query = "Update MyTable SET col1='some value' WHERE id=1 LIMIT 1;";
$query .= "UPDATE MyTable SET col1='other value' WHERE id=2 LIMIT 1;";
//etc
$con->multi_query($query);
$con->close();

希望这有所帮助。

使用

REPLACE INTO`table` VALUES (`id`,`col1`,`col2`) VALUES
(1,6,1),(2,2,3),(3,9,5),(4,16,8);

请注意:

  • id是一个主要独特的关键
  • 如果使用外国的钥匙 参照表,更换删除,然后插入的,因此这可能会 因为一个错误

以下将更新所有行在一个表

Update Table Set
Column1 = 'New Value'

下一个将更新所有行的价值Column2超过5

Update Table Set
Column1 = 'New Value'
Where
Column2 > 5

还有所有 Unkwntech's例的更新多个表

UPDATE table1, table2 SET
table1.col1 = 'value',
table2.col1 = 'value'
WHERE
table1.col3 = '567'
AND table2.col6='567'

是的...它是可能的使用插入关于重复的关键的更新sql statement..语法:插入table_name(a、b、c)价值(第1、2、3),(4、5、6的) 关于重复的关键的更新=值(a)、b=值(b)c=值(c)

PHP我这样做。使用的分号,分为阵列,然后提交经过循环。

$con = new mysqli('localhost','user1','password','my_database');
$batchUpdate = true; /*You can choose between batch and single query */
$queryIn_arr = explode(";", $queryIn);

if($batchUpdate)    /* My SQL prevents multiple insert*/
{
    foreach($queryIn_arr as $qr)
    {
        if(strlen($qr)>3)
        {
            //echo '<br>Sending data to SQL1:<br>'.$qr.'</br>';
            $result = $conn->query($qr);
        }

    }
}
else
{
    $result = $conn->query($queryIn);
}
$con->close();
UPDATE tableName SET col1='000' WHERE id='3' OR id='5'

这应该达到什么找你找的。只增加更多的id's.我已经测试过它。

UPDATE `your_table` SET 

`something` = IF(`id`="1","new_value1",`something`), `smth2` = IF(`id`="1", "nv1",`smth2`),
`something` = IF(`id`="2","new_value2",`something`), `smth2` = IF(`id`="2", "nv2",`smth2`),
`something` = IF(`id`="4","new_value3",`something`), `smth2` = IF(`id`="4", "nv3",`smth2`),
`something` = IF(`id`="6","new_value4",`something`), `smth2` = IF(`id`="6", "nv4",`smth2`),
`something` = IF(`id`="3","new_value5",`something`), `smth2` = IF(`id`="3", "nv5",`smth2`),
`something` = IF(`id`="5","new_value6",`something`), `smth2` = IF(`id`="5", "nv6",`smth2`) 

//你只是建筑在php喜欢

$q = 'UPDATE `your_table` SET ';

foreach($data as $dat){

  $q .= '

       `something` = IF(`id`="'.$dat->id.'","'.$dat->value.'",`something`), 
       `smth2` = IF(`id`="'.$dat->id.'", "'.$dat->value2.'",`smth2`),';

}

$q = substr($q,0,-1);

所以你可以更新孔表一个查询

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top