#mysql #drupal #upsert
#mysql #drupal #ввод
Вопрос:
Я пытался запустить запрос в drupal, который обновит записи, если они уже существуют, или вставит новую запись, если этого не происходит. На данный момент код выглядит следующим образом:
db_query("IF EXISTS (SELECT %d FROM {uc_posten_packages.pid})
UPDATE {uc_posten_packages} SET title = '%s', label = '%s', cost = '%d', length = '%d', width ='%d', height = '%d', weight = '%d' WHERE pid = %d
ELSE
INSERT INTO {uc_posten_packages} VALUES ('%d', '%s', '%s', '%d', '%d', '%d', '%d', '%d')",$id, $title, $label, $rate, $length, $width, $height, $weight, $id, $id, $title, $label, $rate, $length, $width, $height, $weight);
Я не понимаю, почему этот запрос выдает мне ошибку. Все цифры в ошибке верны
...near 'IF EXISTS (SELECT 1 FROM uc_posten_packages.pid) UPDATE uc_posten_packages ' at line 1 query:
IF EXISTS (SELECT 1 FROM uc_posten_packages.pid) UPDATE uc_posten_packages SET title = 'vfbv', label = 'bbv', cost = '22', length = '232', width ='22', height = '22', weight = '22' WHERE pid = 1 ELSE INSERT INTO uc_posten_packages VALUES ('1', 'vfbv', 'bbv', '22', '232', '22', '22', '22')
Должен ли этот запрос работать и / или есть какой-то лучший способ справиться с этим в drupal?
Комментарии:
1. Вы не можете сделать ничего подобного. Взгляните на синтаксис замены. dev.mysql.com/doc/refman/5.0/en/replace.html
Ответ №1:
То, что вы ищете, обычно называется «upsert» (обновление, иначе вставка), и для этого есть функция drupal: db_merge. Хорошая статья здесь:http://drupal.org/node/310085
drupal_write_record() автоматически не выполняет «upsert». Он всегда либо вставляет, либо обновляет только на основе того, что вы передаете, но не на обоих.
Ответ №2:
[ОБНОВЛЕНИЕ январь 2013]
Этот ответ относится к более старой версии Drupal, чем текущая стабильная версия. Пожалуйста, отредактируйте этот ответ, добавив раздел обновления, подобный этому, с более актуальной информацией, поскольку я больше не работаю с Drupal и не слежу за изменениями в его API.
-semperos
[/ ОБНОВЛЕНИЕ от января 2013]
У вас есть несколько вариантов, а именно drupal_write_record
или запуск образца запроса и тестирование результатов. Это не должно выполняться в одном SQL-запросе, как в вашем вопросе.
drupal_write_record (предпочтительный метод)
Функция drupal_write_record
позволяет вам указать таблицу, с которой вы хотите иметь дело, и объект (или ассоциированный массив), который содержит данные для каждого столбца / поля этой таблицы. Если у вас уже есть первичный ключ для строки, которую вы пытаетесь обновить, тогда вы включаете его в качестве третьего параметра в функцию, и drupal_write_record
автоматически будет использоваться команда SQL UPDATE
. В противном случае значение по умолчанию равно INSERT
. Например:
drupal_write_record('uc_posten_packages', array('title' => "Foobar",
'label' => "foobar",
'cost' => 10,
'length' => 100,));
Это INSERT
создаст новую запись с этой информацией. Если бы вы включили третий аргумент, array($pid)
где $pid
было имя поля, которое действует как первичный ключ для таблицы, вместо этого было бы выполнено обновление.
Эта функция будет работать, только если таблица, с которой вы имеете дело, была определена с помощью hook_schema
, что должно быть верно для любого правильно разработанного модуля Drupal, который имеет таблицы базы данных. Поскольку эта функция использует схему для обеспечения правильной записи в базу данных, вы должны использовать эту функцию, когда это возможно (или когда не существует других более специфичных функций, например node_save
для объектов узла).
Тестовый запрос
Вы можете просто запустить пример запроса с помощью db_result(db_query("SELECT..."))
. Он возвращает пустую строку, если результаты не найдены, которая в PHP оценивается как false, поэтому ваш код может выглядеть следующим образом:
if (db_result(db_query("SELECT * FROM {uc_posten_packages} WHERE pid = %d", $pid))) {
// UPDATE
} else {
// INSERT
}
Комментарии:
1. Спасибо за ответ! Это великолепно, но я не могу заставить его обновиться. Я добавил массив ($ pid) в качестве третьего аргумента, но он выдает мне ошибку: неподдерживаемый тип для db_type_placeholder. Он работает со вставками, хотя, точно такой же запрос, но без третьего аргумента.
2. @Toxid Я обновил свой ответ, чтобы быть более точным. Если вы посмотрите на api.drupal.org документы для drupal_write_record, третьим необязательным аргументом должно быть имя поля, которое действует как первичный ключ для таблицы, с которой вы работаете, а не фактическое значение первичного ключа. Смотрите код функции node_save в качестве примера обоих типов drupal_write_record (вставка и обновление) здесь: api.drupal.org/api/drupal/modules—node—node.module/function /…
3. Ах, красиво! Я изучал API, но я был настолько уверен, что это значение первичного ключа, которое он искал, я забыл о возможности того, что это может быть что-то другое. Спасибо!
4. Глядя на исходный код drupal_write_record() я не вижу логики в принятии решения о выполнении запроса INSERT или UPDATE на основе того, что уже есть в БД. Вместо этого я вижу, что это зависит от входных параметров (параметр $ update). Поэтому я бы исправил ответ, удалив всю часть drupal_write_record().
5. Я больше не работаю на PHP или Drupal. Если кто-то хочет отредактировать мой ответ с информацией, относящейся к последней стабильной версии Drupal, я бы приветствовал редактирование. Тем временем я отредактирую ответ, чтобы уточнить, что этот ответ устарел.
Ответ №3:
Согласно drupal_write_record, операция была UPDATE
или INSERT
вам нужно знать, существовала запись или нет, прежде чем совершать транзакцию. Это не то, что делает drupal_write_record(). Эта функция просто проверяет свои аргументы и выдает обновление или вставку соответственно. Таким образом, на самом деле нет способа определить, выполнила ли функция INSERT
или an UPDATE
.
Решение заключается в использовании запроса db_merge(), это относительно новый стандарт SQL ANSI, который делает именно то, что мне было нужно (и в случае MySQL делает это в атомной транзакции).
$return_value = db_merge('mytable')
->key(array('id' => $key))
->fields($fields)
->updateFields(array(
'updatedon' => $now,
))
->execute();
Возвращаемое значение представляет собой целое число, возвращающее 1 для вставок и 2 для обновлений.
Ответ №4:
Это глупый пример синтаксиса замены.
mysql> create table test (
-> id int,
-> a int,
-> b int,
-> unique (id)
-> ) engine = myisam;
Query OK, 0 rows affected (0.01 sec)
mysql> replace into test (id,a,b) values (1,4,2);
Query OK, 1 row affected (0.00 sec)
mysql> replace into test (id,a,b) values (2,10,3);
Query OK, 1 row affected (0.00 sec)
mysql> select * from test;
------ ------ ------
| id | a | b |
------ ------ ------
| 1 | 4 | 2 |
| 2 | 10 | 3 |
------ ------ ------
2 rows in set (0.00 sec)
mysql> replace into test (id,a,b) values (1,5,5);
Query OK, 2 rows affected (0.00 sec)
mysql> select * from test;
------ ------ ------
| id | a | b |
------ ------ ------
| 1 | 5 | 5 |
| 2 | 10 | 3 |
------ ------ ------
2 rows in set (0.00 sec)
Надеюсь, это могло бы вам помочь.