预准备语句与 ON 重复键

2022-08-30 20:34:54

我认为这应该很容易,但我很难把它做好。我已经搜索了一下,但是作为准备语句的新手,我无法通过查看我在这里和其他地方找到的其他示例来完全弄清楚语法。无论如何,这是我的代码。

if($stmt = $mysqli -> prepare("INSERT INTO user_info (city, state, website, public_contact, user, zipcode, pic, emailme) VALUES (?, ?, ?, ?, ?, ?, ?,?) 
    ON DUPLICATE KEY UPDATE (city, state, website, public_contact, user, zipcode, pic, emailme) VALUES (?, ?, ?, ?, ?, ?, ?,?)")) {
    $stmt -> bind_param("sssssssi",$city, $state, $website, $public_contact, $user, $zipcode, $pic, $emailme);
    $stmt -> execute();
    $stmt -> bind_result($result);
    $stmt -> close();
}

用户是唯一的。这个IMO只是一个语法问题,所以有人可以用正确的语法帮助我吗?非常感谢。

ETA:只是为了帮助解决问题,当我删除重复键更新部分时,这确实按预期工作,但显然,它只允许每个用户一条记录并且不会更新

更新:永远无法找到使用ON DUPLICATE KEY UPDATE的工作语法,所以我所做的(诚然可能不是最有效的方法)是在用户之前检查表。如果用户存在,我运行并更新,如果没有,我运行插入。以下是我的工作代码。希望这有助于那些陷入我处境的人。

 $sql = "SELECT * FROM user_info WHERE user='$user'";

 if ($result=mysqli_query($mysqli,$sql))
 {
 /* Return the number of rows in result set */
 $rows=mysqli_num_rows($result);
 /* Free result set */
 mysqli_free_result($result);
 } 

 if($rows == 0) { 
if($stmt = $mysqli -> prepare("INSERT INTO user_info (city, state, website, public_contact, user, zipcode, pic, emailme) VALUES (?, ?, ?, ?, ?, ?, ?,?) ")) {

$stmt -> bind_param("sssssssi",$city, $state, $website, $public_contact, $user, $zipcode, $pic, $emailme);
$stmt -> execute();
$stmt -> bind_result($result);
$stmt -> close();
}

} else {

if($stmt = $mysqli -> prepare("UPDATE user_info SET city=?, state=?, website=?, public_contact=?, zipcode=?, pic=?, emailme=? WHERE user='$user'")) {

$stmt -> bind_param("ssssssi",$city, $state, $website, $public_contact, $zipcode, $pic, $emailme);
$stmt -> execute();
$stmt -> bind_result($result);
$stmt -> close();
}
    }

答案 1

最简单的方法来使用 INSERT...在重复密钥更新上,将按以下方式使用 VALUES 子句,因此您无需重复 UPDATE 子句中的参数。它们只对您在 VALUES 子句中传递的每列使用相同的值:

if($stmt = $mysqli -> prepare("
    INSERT INTO user_info (city, state, website, public_contact, 
        user, zipcode, pic, emailme)
    VALUES (?, ?, ?, ?, ?, ?, ?, ?) 
    ON DUPLICATE KEY UPDATE
        city = VALUES(city),
        state = VALUES(state),
        website = VALUES(website),
        public_contact = VALUES(public_contact),
        user = VALUES(user),
        zipcode = VALUES(zipcode),
        pic = VALUES(pic),
        emailme = VALUES(emailme)") {
    $stmt -> bind_param("sssssssi",$city, $state, $website, $public_contact, 
        $user, $zipcode, $pic, $emailme);
    $stmt -> execute();
    $stmt -> close();
}

IODKU 语法要求您单独设置每列。你不能像你试图做的那样,把它们全部列在一个子句中。

您应该始终报告对 prepare() 或 execute() 的任何调用中的任何错误。或者你可以让mysqli抛出异常:

$mysqli -> report_mode = MYSQLI_REPORT_STRICT;

此外,您不需要bind_result(),因为 INSERT 中没有结果集:

// NO: $stmt -> bind_result($result);

答案 2

我强烈建议你看看像Toriness DBAL(不是ORM)这样的东西 - 它允许你去堆键=>值对,并使这些类型的操作在有这么多值时更容易使用。

然后,您可以执行如下操作:

try {
    $conn->insert(
    'db.`table`',
     [
       'city' => $city,
       'state' => $state
     ]);
} catch (Exception $e) {

    if( $e->getCode() !== '23000' ) {
        throw $e;
    }

    $conn->update(
    'db.`table`',
     [
       'city' => $city,
       'state' => $state
     ],
     [
       'user' => $user
     ]);
}

推荐