wpdb->prepare и MySQL UPDATE - как это делается?
Пытаюсь установить дату и время удаления в запросе плагина, но не уверен, как использовать UPDATE SET с $wpdb->prepare.
Вот мой запрос:
$cur_date = date('Y-m-d G:i:s');
$rows_affected = $wpdb->query(
$wpdb->prepare("
UPDATE $table
SET ( removed, post_id, user_id, status )
VALUES ( %s, %d, %d, %d )
"),
array($cur_date, $postid, $userid, 0)
));
Могу ли я настроить UPDATE таким образом, используя $wpdb? Я совсем новичок в создании собственных запросов к БД.
Если нет, как я должен/могу это сделать?
Заранее спасибо!
РЕДАКТИРОВАНИЕ ---------------------------------------------------
Новый код:
$table = $wpdb->prefix . 'ds_entry_swoons';
$cur_date = date('Y-m-d G:i:s');
$rows_affected = $wpdb->query(
$wpdb->prepare("
UPDATE {$table}
SET removed = %s, post_id = %d, user_id = %d, swoon_status = %d
WHERE post_id = $postid AND user_id = $userid;",
$cur_date, $postid, $userid, 0
)
);

Существует специальный метод $wpdb->update()
, который является удобным помощником для выполнения запроса UPDATE
, а также выполняет санитизацию данных, вызывая $wpdb->prepare()
внутренне.

Вы правы, @Rarst, исходный код wpdb::update: ... return $this->query( $this->prepare( $sql, $values ) );
: https://developer.wordpress.org/reference/classes/wpdb/update/

Я немного исправил ваш запрос. Ему нужна таблица и условие WHERE, чтобы предотвратить изменение всех строк. Даже LIMIT 1 в конце не помешает.
$rows_affected = $wpdb->query(
$wpdb->prepare(
"UPDATE {$table} SET removed = %s, post_id = %d, user_id = %d, status = %d;",
$cur_date = date('Y-m-d H:i:s'), $postid, $userid, 0
) // $wpdb->prepare
); // $wpdb->query
Просто добавьте WHERE... в MySQL-запрос. Правильное использование prepare:
$wpdb->prepare($format, $arg1, $arg2, ...); // аналогично printf()

LIMIT 1 в операторах UPDATE и DELETE может быть очень опасным. Особенно это актуально, если база данных является мастером в настройке репликации MySQL, потому что нет гарантии порядка выполнения UPDATE/DELETE на реплике. Предупреждения об этом будут записаны в журнал ошибок MySQL на мастере. В остальном ваш ответ по сути верен, как только @dkmojo добавит условие WHERE. +1 !!!

Если вы указываете первичный ключ ID или комбинацию уникальных ключей... почему это было бы опасно?

Это было бы единственным исключением. С неуникальными ключами ситуация была бы иной. MySQL все равно может записывать предупреждения в журнал ошибок в любом случае.

Я даже написал пост об этом в DBA StackExchange: http://dba.stackexchange.com/questions/1371/problem-with-mysql-subquery/1384#1384. Это связано с тем, как MySQL Optimizer выполняет преобразования запросов под капотом.

Верно, но это должно быть осознанным решением. Если вы знаете, что планируете обновить одну запись, насколько мне известно, хорошей практикой является установка LIMIT 1. Если у вас переменное количество записей для обновления, никогда не используйте LIMIT, так как сортировка по умолчанию... не отсортирована :)

На сайте MySQL есть багрепорты для версий 4.0 (закрыт: http://bugs.mysql.com/bug.php?id=1024) и 5.1 (патч применён год назад: http://bugs.mysql.com/bug.php?id=42415) относительно использования UPDATE/DELETE с LIMIT. Даже со всеми исправлениями багов вокруг LIMIT, репликация MySQL на Slave-сервере всё ещё может пострадать. Я узнал об этом просто из порядка SELECT-записей: http://dba.stackexchange.com/q/6051/877.

Использование LIMIT также может включать временные таблицы, если запрос этого требует. Все временные таблицы, создаваемые запросами, по своей природе не отсортированы, как вы уже отмечали ранее. LIMIT проходит через такие временные таблицы, из-за чего порядок выполнения и доступа отличается между Master и Slave.

Спасибо за подробный отзыв! Я добавил условие WHERE и разместил отредактированный код выше. Но не уверен, для чего нужны фигурные скобки '{}' вокруг $table и нужны ли они вообще. В других моих запросах они не используются. Для чего нужны '{}'? Ещё раз спасибо!

@dkmojo {$variable} — это правильный способ использования переменных в "строках" для полного контроля и избежания нежелательных символов при парсинге. (Читайте здесь)[http://php.net/manual/en/language.types.string.php]. Ознакомьтесь с разделами Простой синтаксис и Сложный (фигурный) синтаксис (найдите в тексте на указанной странице). (Например: $table = "{$wpdb->prefix}ds_entry_swoons";)

Вы можете вставить столько переменных, сколько нужно (%d
для цифр, %s
для строк ...)
global $wpdb;
$zz = $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->postmeta
SET meta_value = '%s' WHERE post_id = '%d' OR WHERE post_id = '%d' ",
$value, $id_1, $id_2 ) );
var_dump($zz); exit;
