WPDB вставка или обновление, если существует
Я не слишком хорошо знаком с WPDB или SQL в целом, но у меня есть пользовательская таблица для моего проекта, и я пытаюсь присвоить ей некоторые метаданные. Что бы я "хотел", чтобы произошло: если строка существует - обновить её, если нет - вставить новую. Я прочитал про Insert и Update в документации WPDB, но ни один из них не рассматривал ситуацию "либо то, либо другое". Я думал, что смогу работать с update, поэтому мой код пока выглядит так:
// Обновление записи в таблице
$wpdb->update(
$wpdb->prepare(
$wpdb->prefix.'item_info',
array(
'post_id' => $post_id,
'item_stock' => $item_stock
),
array('post_id' => $post_id)
)
);
Есть ли в WordPress что-то вроде "ЕСЛИ существует - обновить, ИНАЧЕ - вставить", или мне нужно выполнять пользовательский SQL-запрос для достижения этого, или мне нужно сначала сделать запрос к базе данных, чтобы проверить, существует ли ID в моей таблице, а ЗАТЕМ решить, обновлять его или вставлять?
Вы пробовали использовать $wpdb->replace? Согласно WP Codex:
Заменяет строку в таблице, если она существует, или вставляет новую строку, если такой строки еще нет.
Я сам использовал этот метод в нескольких плагинах, и он отлично справляется с предотвращением ошибок дублирования уникальных ID и подобных проблем.
Это сработало для меня, в то время как пользовательский запрос не сработал — спасибо за упоминание replace()
trainoasis
стоит отметить, что $wpdb->replace полностью перезаписывает всю запись, тогда как $wpdb->update обновляет только указанные поля из массива $data
MatthewLee
Эта функция сейчас не выполняет замену для меня. Она дублирует одни и те же строки. Может ли PRIMARY KEY (id) быть причиной, которая препятствует замене? Я не могу найти информацию об этом в Codex.
Viktor Borítás
Я разобрался: чтобы избежать проблемы с заменой, также необходимо применить ограничение UNIQUE к определенным столбцам при создании таблицы, что делает возможным создание уникальных строк.
Viktor Borítás
Во-первых, вы используете prepare неправильно. Похоже, что вы обернули аргументы $wpdb->update в $wpdb->prepare таким образом. Это не сработает. Фактически, вы передаёте в update только один аргумент — результат выполнения prepare. Попробуйте что-то простое, например, следующее, и вы поймёте, почему это не работает:
$post_id = 123;
$item_stock = 567;
var_dump(
$wpdb->prepare(
$wpdb->prefix.'item_info',
array(
'post_id' => $post_id,
'item_stock' => $item_stock
),
array('post_id' => $post_id)
)
);
Кроме того, $wpdb->update() сам выполняет prepare за вас.
Во-вторых, если бы это был я, я бы избегал излишней сложности с вспомогательными функциями и написал бы правильный запрос ON DUPLICATE KEY UPDATE:
$sql = "INSERT INTO {$wpdb->prefix}item_info (post_id,item_stock) VALUES (%d,%s) ON DUPLICATE KEY UPDATE item_stock = %s";
// var_dump($sql); // отладка
$sql = $wpdb->prepare($sql,$post_id,$item_stock,$item_stock);
// var_dump($sql); // отладка
$wpdb->query($sql);
Это предполагает, что post_id является UNIQUE индексом или PRIMARY KEY. Если структура вашей таблицы соответствует моим предположениям, позвольте базе данных разобраться с этим.
Метод prepare возвращает false для меня - других ошибок БД нет. Если выполнить запрос вручную через phpmyadmin, все работает как ожидалось. Также проверил, что переменные содержат правильные значения.. Есть идеи?
trainoasis
Вы можете попробовать обновить таблицу с помощью $wpdb->update. В следующем коде я использую id, но вы можете использовать любые критерии.
$result = $wpdb->update($tableName, $info, array('id' => $info["id"]));
// Если не найдено записей для обновления, попытается создать запись.
if ($result === FALSE || $result < 1) {
$wpdb->insert($tableName, $info);
}
Результат работы Update()
$result === FALSE: Ошибка$result === 0: Успешно, но ничего не обновлено$result > 1: Успешно и обновлено