Как выполнить UPSERT, чтобы я мог использовать как новые, так и старые значения в части обновления - PullRequest
58 голосов
/ 24 мая 2011

Глупый, но простой пример. Предположим, у меня есть таблица «Предмет», где я храню итоги полученных предметов.

Item_Name              Items_In_Stock

Имя элемента здесь является первичным ключом.Как мне добиться следующего, когда я получаю элемент A в количестве X.

Если элемент не существует, я вставляю новый зарегистрированный для элемента A и устанавливаю элементы на складе в X, и если существуетукажите, где на складе было Y, тогда новое значение на складе: (X + Y)

INSERT INTO `item`
(`item_name`, items_in_stock)
VALUES( 'A', 27)
ON DUPLICATE KEY UPDATE
`new_items_count` = 27 + (SELECT items_in_stock where item_name = 'A' )

Моя проблема в том, что в моей фактической таблице есть несколько столбцов.Это хорошая идея написать несколько операторов выбора в части обновления?

Конечно, я могу сделать это в коде, но есть ли лучший способ?

Ответы [ 5 ]

128 голосов
/ 24 мая 2011

Как уже упоминалось в моем комментарии, вам не нужно делать выборку для ссылки на строку, вызывающую срабатывание ON DUPLICATE KEY.Итак, в вашем примере вы можете использовать следующее:

INSERT INTO `item`
(`item_name`, items_in_stock)
VALUES( 'A', 27)
ON DUPLICATE KEY UPDATE
`new_items_count` = `new_items_count` + 27

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

11 голосов
/ 06 сентября 2013

Вы можете получить представление из этого примера:

Предположим, вы хотите добавить данные для семидневных пользователей

Они должны иметь уникальное значение для идентификатора пользователя и дня, например

UNIQUE KEY `seven_day` (`userid`,`day`)

Вот таблица

CREATE TABLE `table_name` (
  `userid` char(4) NOT NULL,
  `day` char(3) NOT NULL,
  `open` char(5) NOT NULL,
  `close` char(5) NOT NULL,
  UNIQUE KEY `seven_day` (`userid`,`day`)
);

И ваш запрос будет

INSERT INTO table_name (userid,day,open,close) 
    VALUES ('val1', 'val2','val3','val4') 
        ON DUPLICATE KEY UPDATE open='val3', close='val4';

Пример:

<?php
//If your data is
$data= array(
        'sat'=>array("userid"=>"1001", "open"=>"01.01", "close"=>"11.01"),
        'sun'=>array("userid"=>"1001", "open"=>"02.01", "close"=>"22.01"),
        'sat'=>array("userid"=>"1001", "open"=>"03.01", "close"=>"33.01"),
        'mon'=>array("userid"=>"1002", "open"=>"08.01", "close"=>"08.01"),
        'mon'=>array("userid"=>"1002", "open"=>"07.01", "close"=>"07.01")
    );


//If you query this in a loop
//$conn = mysql_connect("localhost","root","");
//mysql_select_db("test", $conn);

foreach($data as $day=>$info) {
    $sql = "INSERT INTO table_name (userid,day,open,close) 
                VALUES ('$info[userid]', '$day','$info[open]','$info[close]') 
            ON DUPLICATE KEY UPDATE open='$info[open]', close='$info[close]'";
    mysql_query($sql);
}
?>

Ваши данные будутв таблице:

+--------+-----+-------+-------+
| userid | day | open  | close |
+--------+-----+-------+-------+
| 1001   | sat | 03.01 | 33.01 |
| 1001   | sun | 02.01 | 22.01 |
| 1002   | mon | 07.01 | 07.01 |
+--------+-----+-------+-------+
6 голосов
/ 17 февраля 2017

Хотя ответ Михаэля является правильным, вам нужно знать немного больше, чтобы выполнить установку программно:

Сначала создайте свою таблицу и укажите, для каких столбцов требуется уникальный индекс:

CREATE TABLE IF NOT EXISTS Cell (
  cellId BIGINT UNSIGNED,
  attributeId BIGINT UNSIGNED,
  entityRowId BIGINT UNSIGNED,
  value DECIMAL(25,5),
  UNIQUE KEY `id_ce` (`cellId`,`entityRowId`)
)

Затем вставьте в него некоторые значения:

INSERT INTO Cell VALUES( 1, 6, 199, 1.0 );

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

INSERT INTO Cell VALUES( 1, 6, 199, 1.0 );

Дублирующаяся запись '1-199' для ключа 'id_ce'

Вот почему мы используем команду upsert:

INSERT INTO Cell ( cellId, attributeId, entityRowId, value, s, l, p, t )
VALUES( 1, 6, 199, 300.0 )
ON DUPLICATE KEY UPDATE `value` = `value` + VALUES(`value`)

Thisкоманда принимает значение 1.0, которое уже существует в качестве значения, и выполняет value = value + 300.0.

Так что даже после выполнения вышеупомянутой команды в таблице будет только одна строка, и значение будет 302.0.

0 голосов
/ 26 декабря 2018

Если у вас есть значение для столбца PK или уникального индекса для столбца, который удовлетворяет уникальности, можно использовать INSERT IGNORE, INSERT INTO ... ON DUPLICATE или REPLACE

Пример с INSERT IGNORE

INSERT IGNORE INTO Table1
    (ID, serverID, channelID, channelROLE)
VALUES
    (....);

Пример с INSERT INTO .. ON DUPLICATE KEY UPDATE

SET @id = 1,
    @serverId = 123545,
    @channelId = 512580,
    @channelRole = 'john';
INSERT INTO Table1
    (ID, serverID, channelID, channelROLE)
VALUES
    (@id, @serverId, @channelId, @channelRole)
ON DUPLICATE KEY UPDATE
    serverId = @serverId,
    channelId = @channelId,
    channelRole = @channelRole;

Пример с Replace

REPLACE INTO table1
    (ID, serverID, channelID, channelROLE)
VALUES
    (...);
0 голосов
/ 17 ноября 2013

Это синтаксис для upsert

INSERT INTO `{TABLE}` (`{PKCOLUMN}`, `{COLUMN}`) VALUES (:value)
ON DUPLICATE KEY UPDATE `{COLUMN}` = :value_dup';
...