db_affered_rows в Drupal 7 для db_query

8

Я только что заметил, что @Berdir было так приятно удалить db_affected_rowsиз Drupal 7 . Теперь я задаюсь вопросом, какова лучшая практика для определения того, изменил ли выполненный вами запрос что-либо в базе данных.

Типичный вариант использования будет.

db_query(...);
if (!db_affected_rows()) {
  db_query(...);
}

Я взглянул на объект запроса, возвращенный из db_query, но это не сильно помогло.

Обновление:
я вижу, я был немного неясен относительно того, при каких обстоятельствах я нуждался в информации.

Мой текущий вариант использования довольно прост. У меня есть таблица для типа узла со столбцом nid и некоторыми столбцами данных. У меня есть форма и после отправки формы, я хочу либо вставить или обновить строку в БД.

Проблема с db_update/ db_insertзаключается в том, что если я сначала использую update и вставляю, если update возвращает 0, я не поймаю условие, когда форма была отправлена ​​со значением в БД. Если я сначала использую db_insert, это вызовет ошибку en, если в базе данных уже есть строка.

Я полагаю, что в этом конкретном состоянии я мог бы вставить пустое значение при создании узла, а затем использовать только обновление, но в некоторых случаях это было бы невозможно, если бы мне нужно было хранить информацию, которая была привязана к внешней базе данных. Я также хотел бы избежать зависимости от значений базы данных для моего кода для функционирования.

Моя обычная стратегия для таких случаев - сделать

db_query("INSERT IGNORE INTO ...")
if (!db_affected_rows()) {
  db_query("UPDATE ...");
}

Это просто и безошибочно, независимо от того, в каком состоянии находится БД. Лучший вариант, который я сейчас вижу, - это обработать его с помощью SQL и сделать это:

db_query("INSERT ... ON DUPLICATE KEY UPDATE");

Но я надеялся, что db API сможет справиться с этим.

googletorp
источник

Ответы:

9

Эта информация напрямую возвращается методом execute () в Delete / UpdateQuery, см., Например: UpdateQuery :: execute () .

<?php
$affected = db_update('some_table')
  ->fields(array(
    'some_field' => $value,
  ))
  ->condition('another_field', $id)
  ->execute();
?>

А InsertQuery :: execute () возвращает идентификатор последней вставки.

Berdir
источник
8

Покопавшись, я обнаружил, что Drupal предоставляет готовый инструмент для конкретного случая использования:

Вставьте строку в БД или обновите существующую, если она уже есть.

Это называется запросами слияния , которые могут быть сделаны атомарно для некоторых механизмов БД.

Синтаксис довольно прост:

db_merge('example')
  ->key(array('name' => $name))
  ->fields(array(
    'field1' => $value1,
    'field2' => $value2,
))
->execute();
googletorp
источник
Ах, да, это правильный ответ на ваш обновленный вопрос :) Обратите внимание, что запросы на слияние были переработаны в конце цикла разработки D7, чтобы фактически работать как SQL-запросы MERGE, которые являются частью стандарта SQL 2003, но ни один dbms фактически не реализует его пока Таким образом, все базы данных требуют двух запросов (они сделаны атомарными с помощью транзакций). Проблема с подходом с одним запросом, который использовался для MySQL, заключалась в том, что он полностью игнорировал определение key () и просто работал с уникальными / первичными ключами данной таблицы.
Бердир
@Berdir: Спасибо, что указал мне правильное направление. Я один из тех разработчиков, которым нравится писать SQL и которым трудно привыкнуть к новому db API :)
googletorp
Спасибо за этот указатель. Однако мне все равно пришлось прибегнуть к db_query, так как API-интерфейс Drupal db не позволяет использовать такие константы, как CURRENT_TIMESTAMP (см. Drupal.org/node/215821 )
Whiskey