我对重复更新查询中的插入很困惑.我有MySQL表,结构如下:
如果我的table.person中存在id,或者在此表中插入新记录,我想为person更新some_text和some_other_text值.如果person_id不是PRIMARY,怎么办呢?
Lor*_*nzi 12
您需要一个查询,检查是否存在与record_id(或person_id)相关的任何行.如果存在更新它,否则插入新行
IF EXISTS (SELECT * FROM table.person WHERE record_id='SomeValue')
    UPDATE table.person 
    SET some_text='new_some_text', some_other_text='some_other_text' 
    WHERE record_id='old_record_id'
ELSE
    INSERT INTO table.person (record_id, person_id, some_text, some_other_text) 
    VALUES ('new_record_id', 'new_person_id', 'new_some_text', 'new_some_other_text')
Run Code Online (Sandbox Code Playgroud)
另一个更好的方法是
UPDATE table.person SET (...) WHERE person_id='SomeValue'
IF ROW_COUNT()=0
    INSERT INTO table.person (...) VALUES (...)
Run Code Online (Sandbox Code Playgroud)
        你的问题非常有效.这是一个非常常见的要求.由于MySQL提供的功能,大多数人都会弄错.
PRIMARY密钥存在,否则更新.ON DUPLICATE KEY UPDATEPRIMARY 或任何UNIQUE密钥,否则更新!什么可以发生可怕的错误ON DUPLICATE KEY UPDATE?您使用新的PRIMARY键值(例如UUID)插入一个所谓的新记录,但您的UNIQUE密钥恰好有一个重复值.
你想要的是一个正确的例外,表明你试图将一个副本插入一UNIQUE列.
但你得到的是一个不需要的UPDATE!MySQL将采用冲突记录并开始覆盖其值.如果这种情况无意中发生,则您已经删除了旧记录,并且对旧记录的任何传入引用现在都引用了新记录.由于您可能不会告诉查询更新PRIMARY列,因此无法找到新的UUID.如果您遇到这些数据,它可能没有任何意义,您将不知道它来自何处.
我们需要一个实际 插入PRIMARY的解决方案,除非密钥存在,否则更新.
我们将使用包含两个语句的查询:
PRIMARY键值匹配的位置(影响0或1行).PRIMARY键值不存在则插入(插入1或0行).这是查询:
UPDATE my_table SET
unique_name = 'one', update_datetime = NOW()
WHERE id = 1;
INSERT INTO my_table
SELECT 1, 'one', NOW()
FROM my_table
WHERE id = 1
HAVING COUNT(*) = 0;
Run Code Online (Sandbox Code Playgroud)
这些查询中只有一个会产生影响.这UPDATE很容易.至于INSERT:WHERE id = 1如果id存在则产生一行,如果不存在则没有行.HAVING COUNT(*) = 0如果id是新的,则反转该行,如果已经存在则不生成行.
我已经探索了相同想法的其他变体,例如使用LEFT JOIN和WHERE,但它们看起来更复杂.欢迎改进.
13.2.5.3 INSERT ... ON DUPLICATE KEY UPDATE语法
如果指定ON DUPLICATE KEY UPDATE,并且插入的行将导致UNIQUE索引或PRIMARY KEY中出现重复值,则MySQL将执行旧行的UPDATE.
例:
DELIMITER //
DROP PROCEDURE IF EXISTS `sp_upsert`//
DROP TABLE IF EXISTS `table_test`//
CREATE TABLE `table_test` (
  `record_id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `person_id` INT UNSIGNED NOT NULL,
  `some_text` VARCHAR(50),
  `some_other_text` VARCHAR(50),
  UNIQUE KEY `record_id_index` (`record_id`),
  UNIQUE KEY `person_id_index` (`person_id`)
)//
INSERT INTO `table_test`
  (`person_id`, `some_text`, `some_other_text`)
VALUES
  (1, 'AAA', 'XXX'),
  (2, 'BBB', 'YYY'),
  (3, 'CCC', 'ZZZ')//
CREATE PROCEDURE `sp_upsert`(
  `p_person_id` INT UNSIGNED,
  `p_some_text` VARCHAR(50),
  `p_some_other_text` VARCHAR(50)
)
BEGIN
  INSERT INTO `table_test`
    (`person_id`, `some_text`, `some_other_text`)
  VALUES
    (`p_person_id`, `p_some_text`, `p_some_other_text`)
  ON DUPLICATE KEY UPDATE `some_text` = `p_some_text`,
                          `some_other_text` = `p_some_other_text`;
END//
DELIMITER ;
mysql> CALL `sp_upsert`(1, 'update_text_0', 'update_text_1');
Query OK, 2 rows affected (0.00 sec)
mysql> SELECT
    ->   `record_id`,
    ->   `person_id`,
    ->   `some_text`,
    ->   `some_other_text`
    -> FROM
    ->   `table_test`;
+-----------+-----------+---------------+-----------------+
| record_id | person_id | some_text     | some_other_text |
+-----------+-----------+---------------+-----------------+
|         1 |         1 | update_text_0 | update_text_1   |
|         2 |         2 | BBB           | YYY             |
|         3 |         3 | CCC           | ZZZ             |
+-----------+-----------+---------------+-----------------+
3 rows in set (0.00 sec)
mysql> CALL `sp_upsert`(4, 'new_text_0', 'new_text_1');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT
    ->   `record_id`,
    ->   `person_id`,
    ->   `some_text`,
    ->   `some_other_text`
    -> FROM
    ->   `table_test`;
+-----------+-----------+---------------+-----------------+
| record_id | person_id | some_text     | some_other_text |
+-----------+-----------+---------------+-----------------+
|         1 |         1 | update_text_0 | update_text_1   |
|         2 |         2 | BBB           | YYY             |
|         3 |         3 | CCC           | ZZZ             |
|         5 |         4 | new_text_0    | new_text_1      |
+-----------+-----------+---------------+-----------------+
4 rows in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)