我对重复更新查询插入有点困惑。 我有MySQL的表结构是这样的:针对非主键密钥的重复更新MySQL插入
- RECORD_ID(PRIMARY,UNIQUE)
- 为person_id(唯一的)
- SOME_TEXT
- some_other_text
我想更新SOME_TEXT和some_other_text如果它的id存在于我的table.person中,或者在此表中插入新记录,则返回值。如果person_id不是主要的,它如何完成?
我对重复更新查询插入有点困惑。 我有MySQL的表结构是这样的:针对非主键密钥的重复更新MySQL插入
我想更新SOME_TEXT和some_other_text如果它的id存在于我的table.person中,或者在此表中插入新记录,则返回值。如果person_id不是主要的,它如何完成?
您需要一个查询来检查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')
另一种更好的方法是
UPDATE table.person SET (...) WHERE person_id='SomeValue'
IF ROW_COUNT()=0
INSERT INTO table.person (...) VALUES (...)
13.2.5.3 INSERT ... ON DUPLICATE KEY UPDATE Syntax
如果指定了对重复密钥更新,和行插入该 会在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)
我认为这应该是正确的答案。它效率更高,并且符合MySQL批准的方式。 – reydelleon
你提的问题是非常有效的。这是一个非常普遍的要求。由于MySQL提供的内容,大多数人都错了。
PRIMARY
键存在,否则更新。ON DUPLICATE KEY UPDATE
PRIMARY
或任何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;
这些查询的只有一个会产生作用。 UPDATE
很容易。至于INSERT
:WHERE id = 1
如果id存在,则返回结果;如果不存在,则返回结果。 HAVING COUNT(*) = 0
反转,如果id是新的,则返回一行;如果它已经存在,则返回no行。
我已经探索了相同想法的其他变体,例如LEFT JOIN
和WHERE
,但它们看起来更复杂。欢迎改进。
我的方法如何?
假设您有一张带有自动增量id和三个文本列的表格。您想要插入/更新column3的值,并将column1和column2中的值作为(非唯一)键。
我使用此查询(无明确锁定表):
insert into myTable (id, col1, col2, col3)
select tmp.id, 'col1data', 'col2data', 'col3data' from
(select id from myTable where col1 = 'col1data' and col2 = 'col2data' union select null as id limit 1) tmp
on duplicate key update col3 = values(col3)
什么不对?对我而言,它的工作方式是我想要的。
[@@ ROWCOUNT](https://msdn.microsoft.com/en-us/library/ms187316.aspx)或[ROW_COUNT()](https://dev.mysql.com/doc/refman/) 5.7/EN /信息functions.html#function_row数)? – wchiquito
@@ ROW_COUNT()抱歉。 @@ ROWCOUNT for SQL Server @wchiquito – fattidare
@fattidare检查是否存在另一个工作解决方案 - 没关系,谢谢 – moonvader