foreach与mysqli_multi_query问题

时间:2016-10-06 13:24:59

标签: php mysql arrays mysqli mysqli-multi-query

我有以下代码可以正常工作并更新数组中包含的每条记录:

$check_list = isset($_POST['check_list']) ? $_POST['check_list'] : array();  
foreach($check_list as $check_list) {
$query = "UPDATE `stock` SET `signature_id` = 0, 
                              user_id = 0, 
                             `status_id` = 1 
            WHERE `id` = '$check_list'";
$result = mysqli_query($conn, $query);

我现在需要它为数组中的每个结果执行多个查询,所以我使用mysqli_multi_query将代码更改为以下内容:

$check_list = isset($_POST['check_list']) ? $_POST['check_list'] : array();  
foreach($check_list as $check_list) {
    $query = "UPDATE `stock` SET `signature_id` = 0, 
                                  user_id = 0, 
                                 `status_id` = 1 
                WHERE `id` = '$check_list';
               INSERT INTO `returned`
                        (`id`, `stock_id`, `signature_id`, 
                        `user_id`, `timestamp`) 
                VALUES ('','$check_list','$id',
                        '$user_id',now())";
    $result = mysqli_multi_query($conn, $query);

但它现在只对数组中的第一条记录执行一次UPDATE和一次INSERT,并忽略其他记录

1 个答案:

答案 0 :(得分:1)

由于可重用性和安全性,@ RiggsFolly提供了有关准备参数化语句和交易的最佳建议,但如果您希望/需要留在mysqli_multi_query,(因为您不想转换)在项目中期进行新的查询过程,或者因为它对你没有吸引力)这里是mysqli_multi_query可以为你服务的方式:

查询组合:

如果SET值保持不变且只有id不同,则所有UPDATE查询都可以合并为单个查询。如果值是静态的,则可以使用implode(),否则可以在单个查询的SET子句中使用(详细/丑陋)CASE语句,或者在原始帖子中创建多个UPDATE查询。

$queries="UPDATE `stock` SET `signature_id`=0,`user_id`=0,`status_id`=1 WHERE `id` IN (".implode(',',$check_list).");";

与INSERT查询类似,它们都可以合并到一个带有implode()的语句或一个仅扩展VALUE部分的foreach循环。

$queries.="INSERT INTO `returned` (`stock_id`,`signature_id`,`user_id`,`timestamp`) VALUES ('".implode("','$id','$user_id',now()),('",$check_list)."','$id','$user_id',now());";

$queries.="INSERT INTO `returned` (`stock_id`,`signature_id`,`user_id`,`timestamp`) VALUES ";
foreach($check_list as $k=>$check_list){
    // manipulate $id and $user_id as needed
    $queries.=($k==0?"":",")."('$check_list','$id','$user_id',now())";
}

失败意识:

如果你不需要任何成功的迹象,那么单行将会做(当然不在任何循环之外):

mysqli_multi_query($conn,$queries)

否则,您需要稍微大一点的代码:

if(mysqli_multi_query($conn,$queries)){
    do{
        echo "<br>Rows = ",mysqli_affected_rows($conn);
    } while(mysqli_more_results($conn) && mysqli_next_result($conn));
}
if($mysqli_error=mysqli_error($conn)){
    echo "<br>Syntax Error: $mysqli_error";
}   

我已经使用implode()测试了我的解决方案,并且使用了以下方法成功:

$check_list=array(1,3,5,6,10,11);

和数据库设置:

CREATE TABLE `stock` (
    id int(10) NOT NULL AUTO_INCREMENT,
    signature_id int(10) NOT NULL,
    user_id int(10) NOT NULL,
    status_id int(10) NOT NULL,
    PRIMARY KEY (id)
);

CREATE TABLE `returned` (
    id int(10) NOT NULL AUTO_INCREMENT,
    stock_id int(10) NOT NULL,
    signature_id int(10) NOT NULL,
    user_id int(10) NOT NULL,
    `timestamp` datetime NOT NULL,
    PRIMARY KEY (id)
);

/* Declaring your `id` columns with AUTO_INCREMENT means you can omit them from your INSERT query. */
/* Depending on your mysql version, creating a default datetime for `timestamp` may be possible which then would permit omitting `timestamp` from your INSERT query too. */

INSERT INTO `stock` (`signature_id`,`user_id`,`status_id`) VALUES
    (1,1,1),
    (2,2,2),
    (3,3,3),
    (4,4,4),
    (5,5,5),
    (6,6,6),
    (7,7,7),
    (8,8,8),
    (9,9,9),
    (10,10,10),
    (11,11,11),
    (12,12,12);

构建的查询如下所示:

UPDATE `stock` SET `signature_id`=0,`user_id`=0,`status_id`=1 WHERE `id` IN (1,3,5,6,10,11);INSERT INTO `returned` (`stock_id`,`signature_id`,`user_id`,`timestamp`) VALUES ('1','','',now()),('3','','',now()),('5','','',now()),('6','','',now()),('10','','',now()),('11','','',now());