27 февраля 2006

ON DUPLICATE KEY UPDATE ещё круче

Я уже писал, как можно заменить связку из трёх запросов SELECT-INSERT-UPDATE на один запрос INSERT-SELECT FROM-ON DUPLICATE KEY UPDATE. Так же я тогда отметил о таком не очень удобном моменте, как необходимость нагенеривать данные для запроса: как для INSERT-блока, так и для UPDATE-блока. Например, в данный момент я ковыряю кусок кода, который либо добавляет нового подписчика, либо обновляет данные существующего:
<?
$sql = "INSERT INTO `subscription` (`email`, `id_language`, `id_currency`)
VALUES ('".$email."',".$language.",".$currency.")
ON DUPLICATE KEY UPDATE
`id_language`=".$language.",
`id_currency`=".$currency;
?>

Видите? Бедному РНР нужно подставить значения переменных не только в INSERT, но и в UPDATE. Чем это плохо? Во-первых, если придётся ковырять этот код в следующий раз, например, перед значениями $language и $currency приписать (int), чтобы явно привести их к целому типу, то придётся сделать 4 правки. Во-вторых, работы для PHP-сервера больше: одно дело просто строчку скопировать, другое - проставлять значения переменных. Столбцов может быть не 2-3, а 20, да плюс несколько таких запросов (в цикле) - тогда это может быть значительно.

Чтобы в этой ситуации облегчить работу PHP-серверу и немного больше напрячь ленивый SQL-сервер, есть функция VALUES(). Она позволяет, в данном случае, обратиться в UPDATE-блоке к данным из INSERT-блока. Таким образом, код становится чище:
<?
$sql = "INSERT INTO `subscription` (`email`, `id_language`, `id_currency`)
VALUES ('".$email."',".$language.",".$currency.")
ON DUPLICATE KEY UPDATE
`id_language`=VALUES(`id_language`),
`id_currency`=VALUES(`id_currency`)";
?>

8 комментов:

Анонимный комментирует...

реал!

Анонимный комментирует...

А чем этот запрос отличается от REPLACE кроме того, что он намного сложнее?

A4 комментирует...

Это разные вещи.

В этой статье описан INSERT + optional UPDATE.

A REPLACE = DELETE + INSERT. Плюс как следствие REPLACE меняет айдишники.

Анонимный комментирует...

здесь более подробно описано инсерт-апдэйт )))
http://www.weblibrary.biz/mysql/sintaksis-oper/oper-manipul-dannymi/sintaksis-insert

Nikolay комментирует...

Вот еще круче:

INSERT INTO `subscription` (`email`, `id_language`, `id_currency`)
VALUES
('1','aaa','bbb'),
('2','ccc','ddd'),
('3','eee','fff')
ON DUPLICATE KEY UPDATE
`id_language`=VALUES(`id_language`),
`id_currency`=VALUES(`id_currency`)

Апдэйтим или инсертим сразу несколько строк =)

Nikolay комментирует...

Еще круче:

INSERT INTO `subscription` (`email`, `id_language`, `id_currency`)
VALUES
('".$email[0]."',".$language[0].",".$currency[0]."),
('".$email[1]."',".$language[1].",".$currency[1]."),
('".$email[2]."',".$language[2].",".$currency[2].")
ON DUPLICATE KEY UPDATE
`id_language`=".$language.",
`id_currency`=".$currency;

Star комментирует...

я, надеюсь, ты имел ввиду следующее?

<?
$sql = "INSERT INTO `subscription` (`email`, `id_language`, `id_currency`)
VALUES
('".$email[0]."',".$language[0].",".$currency[0]."),
('".$email[1]."',".$language[1].",".$currency[1]."),
('".$email[2]."',".$language[2].",".$currency[2].")
ON DUPLICATE KEY UPDATE
`id_language`=VALUES(`id_language`),
`id_currency`=VALUES(`id_currency`)";
?>

1_and_0 комментирует...

Чего там про цыклы говорили??

foreach($data as $v) $add_sql[] = "('{$v[0]}',{$v[1]},$v[2])";

$sql = $sql = "INSERT INTO `subscription` (`email`, `id_language`, `id_currency`)
VALUES ".implode(',',$add_sql)."
ON DUPLICATE KEY UPDATE
`id_language`=VALUES(`id_language`),
`id_currency`=VALUES(`id_currency`)";

Отправить комментарий