我對重複更新查詢插入有點困惑。 我有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