Подготовленный отчет с ключом ON DUPLICATE
Я думаю, что это должно быть довольно легко, но у меня возникают проблемы с этим. Я немного искал, но был новичком в подготовленных утверждениях. Я не могу понять синтаксис, глядя на другие примеры, которые я нашел здесь и в других местах. В любом случае, вот мой код.
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();
}
пользователь является уникальным. Эта ИМО - это просто синтаксическая проблема, поэтому кто-нибудь может помочь мне с правильным синтаксисом? Очень признателен.
ETA: просто для того, чтобы помочь устранить проблему, это работает по назначению, когда я удаляю часть ON DUPLICATE KEY UPDATE, но, очевидно, она разрешает только одну запись для каждого пользователя и не будет обновлять
UPDATE: никогда не мог найти рабочий синтаксис для использования UPDATE ON DUPLICATE KEY UPDATE, поэтому то, что я сделал (по общему мнению, возможно, не самый эффективный способ), проверял таблицу перед рукой для пользователя. Если пользователь существует, я запускаю и UPDATE, если нет, я запускаю INSERT. Ниже мой рабочий код. Надеюсь, это поможет кому-то, кто застрял в моей ситуации.
$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... ON DUPLICATE KEY UPDATE - использовать предложение 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 требует, чтобы каждый столбец был установлен отдельно. Вы не можете перечислить их все в одном пункте, как вы пытались сделать.
Вы всегда должны сообщать о любых ошибках из любого вызова для подготовки() или execute(). Или вы можете сделать исключения mysqli throw:
$mysqli -> report_mode = MYSQLI_REPORT_STRICT;
Кроме того, вам не нужно bind_result(), так как нет набора результатов из INSERT:
// NO: $stmt -> bind_result($result);
Ответ 2
Я бы настоятельно предложил взглянуть на что-то вроде Doctrine 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
]);
}