我知道您可以一次插入多行,是否可以在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;

===============>>#1 票数:606 已采纳

是的,这是可能的-您可以在插入的键更新中使用INSERT...。

使用您的示例:

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);

===============>>#2 票数:116

由于您具有动态值,因此需要对要更新的列使用IF或CASE。 它有点难看,但应该可以。

使用您的示例,您可以这样做:

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);

===============>>#3 票数:84

这个问题很旧,但是我想用另一个答案扩展话题。

我的观点是,最简单的方法是用事务包装多个查询。 可接受的答案INSERT ... ON DUPLICATE KEY UPDATE是一个不错的技巧,但您应该意识到它的缺点和局限性:

  • 可以这么说,如果您碰巧以表中不存在主键的行启动查询,则查询会插入新的“半熟”记录。 可能不是您想要的
  • 如果您的表具有不带默认值的非空字段,并且不想在查询中触摸此字段,那么即使您不这样做,也会收到"Field 'fieldname' doesn't have a default value" MySQL警告完全不插入一行。 如果您决定严格执行,并将mysql警告转换为应用程序中的运行时异常,它将惹上麻烦。

我对三个建议的变体进行了性能测试,包括INSERT ... ON DUPLICATE KEY UPDATE变体,带有“ case / when / then”子句的变体和带有事务处理的幼稚方法。 您可以在此处获取python代码和结果。 总的结论是,带有case语句的变体的速度是其他两个变体的两倍,但是很难为其编写正确且注入安全的代码,因此我个人坚持最简单的方法:使用事务。

编辑: Dakusan的发现证明了我的绩效评估不是很有效。 请参阅此答案以进行其他更详尽的研究。

===============>>#4 票数:61

不知道为什么还没有提到另一个有用的选项:

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;

===============>>#5 票数:32

以下所有内容均适用于InnoDB。

我觉得了解3种不同方法的速度非常重要。

有3种方法:

  1. INSERT:使用ON DUPLICATE KEY UPDATE插入
  2. 交易:您对交易中的每条记录进行更新的位置
  3. 案例:在这种情况下/对于UPDATE中的每个不同记录

我刚刚进行了测试,而INSERT方法对我来说比TRANSACTION方法快6.7倍 我尝试了3,000行和30,000行的集合。

TRANSACTION方法仍然必须运行每个单独的查询,这会花费一些时间,尽管它会在执行时将结果批处理到内存中。 在复制和查询日志中,TRANSACTION方法也非常昂贵。

更糟糕的是,CASE方法的速度比INSERT方法慢了41.1倍 ,具有30,000条记录(比TRANSACTION慢6.1倍)。 而MyISAM的速度要慢75倍 INSERT和CASE方法收支平衡,达到约1,000条记录。 即使有100条记录,CASE方法也快得多。

因此,总的来说,我觉得INSERT方法既是最好的也是最容易使用的。 这些查询较小,更易于阅读,仅占用1个操作查询。 这适用于InnoDB和MyISAM。

奖励的东西:

INSERT非默认字段问题的解决方案是暂时关闭相关的SQL模式: SET SESSION sql_mode=REPLACE(REPLACE(@@SESSION.sql_mode,"STRICT_TRANS_TA‌​BLES",""),"STRICT_AL‌​L_TABLES","") 如果计划还原,请确保先保存sql_mode

至于其他评论,我已经看到说使用INSERT方法提高了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).';');
}

===============>>#6 票数:8

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

这应该为您工作。

MySQL手册中有多个表的参考。

===============>>#7 票数:8

使用临时表

// 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`");
}

===============>>#8 票数:3

您可以为同一张表加上别名,以为您要插入的ID(如果要进行逐行更新:

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

此外,很明显,您也可以从其他表进行更新。 在这种情况下,更新将兼作“ SELECT”语句,从而为您提供来自指定表的数据。 您在查询中明确说明了更新值,因此第二个表不受影响。

===============>>#9 票数:3

为什么没有人在一个查询中提到多个语句

在php中,您使用mysqli实例的multi_query方法。

PHP手册

MySQL可选地允许在一个语句字符串中包含多个语句。 一次发送多个语句可以减少客户端与服务器之间的往返,但需要特殊处理。

这是在更新30,000 raw中与其他3种方法进行比较的结果。 可以在这里找到基于@Dakusan的答案的代码

交易:5.5194580554962
插入:0.20669293403625
案例:16.474853992462
多:0.0412278175354

如您所见,多语句查询比最高答案更有效。

如果收到这样的错误消息:

PHP Warning:  Error while sending SET_OPTION packet

您可能需要在我的机器上为/etc/mysql/my.cnf mysql配置文件中增加max_allowed_packet ,然后重新启动mysqld。

===============>>#10 票数:2

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

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.

编辑:如果您要更新的值不是来自数据库中的其他位置,则需要发出多个更新查询。

===============>>#11 票数:2

您可以更改一个名为“ multi statement”的设置,该设置将禁用MySQL的“安全机制”,以防止(多个)注入命令。 这是MySQL的“出色”实现的典型特征,它还阻止用户执行有效的查询。

这里( http://dev.mysql.com/doc/refman/5.1/en/mysql-set-server-option.html )是有关设置的C实现的一些信息。

如果您使用的是PHP,则可以使用mysqli来执行多条语句(我认为phpi已随mysqli一起发布了一段时间)

$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();

希望能有所帮助。

===============>>#12 票数:-1

采用

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

请注意:

  • id必须是主唯一键
  • 如果使用外键引用该表,则REPLACE删除然后插入,因此可能会导致错误

===============>>#13 票数:-3

是的..使用INSERT ON DUPLICATE KEY UPDATE sql语句是可能的..语法:INSERT INTO table_name(a,b,c)VALUES(1,2,3),(4,5,6)ON DUPLICATE KEY UPDATE a = VALUES(a),b = VALUES(b),c = VALUES(c)

===============>>#14 票数:-3

以下将更新一个表中的所有行

Update Table Set
Column1 = 'New Value'

下一个将更新Column2的值大于5的所有行

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

Unkwntech提供了所有更新多个表的示例

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

===============>>#15 票数:-4

使用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();

===============>>#16 票数:-5

UPDATE tableName SET col1='000' WHERE id='3' OR id='5'

这应该可以实现您想要的。 只需添加更多ID。 我已经测试过了

===============>>#17 票数:-7

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);

因此您可以使用一个查询更新孔表

  ask by Teifion translate from so

未解决问题?本站智能推荐: