Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MySQL INSERT ON DUPLICATE KEY UPDATE ... return "rows affected: 1", but no changes really

I create table with column which have default value '1'

create table int_1 (
  id int not null auto_increment,
  value int default 1,
  primary key (id)
);

command

insert into int_1 values(1, null) on duplicate key update value = null;

always return result

1 row(s) affected

but record really changed (inserted) after first execution. But if i create table with default value '0', all works as expected:

create table int_0 (
  id int not null auto_increment,
  value int default 0,
  primary key (id)
);
insert into int_0 values(1, null) on duplicate key update value = null;

return

0 row(s) affected

after second run "insert on duplicate key"

Checked on MySQL 5.7, 8.0

Is there an explanation for this behavior?

like image 307
bald2b Avatar asked Apr 18 '19 16:04

bald2b


People also ask

How does on duplicate key update work?

ON DUPLICATE KEY UPDATE inserts or updates a row, the LAST_INSERT_ID() function returns the AUTO_INCREMENT value. The ON DUPLICATE KEY UPDATE clause can contain multiple column assignments, separated by commas. The use of VALUES() to refer to the new row and columns is deprecated beginning with MySQL 8.0.

Is insert on duplicate key update Atomic?

By definition, atomicity requires that each transaction is an all or nothing. So yes it is atomic in the sense that if the data that you are trying to insert will cause a duplicate in the primary key or in the unique index, the statement will instead perform an update and not error out.

How do I use Upsert in MySQL?

We can perform MySQL UPSERT operation mainly in three ways, which are as follows: UPSERT using INSERT IGNORE. UPSERT using REPLACE. UPSERT using INSERT ON DUPLICATE KEY UPDATE.

How can I add duplicate rows in MySQL?

Use the INSERT IGNORE command rather than the INSERT command. If a record doesn't duplicate an existing record, then MySQL inserts it as usual. If the record is a duplicate, then the IGNORE keyword tells MySQL to discard it silently without generating an error.


2 Answers

With ON DUPLICATE KEY UPDATE, the affected-rows value per row is 1 if the row is inserted as a new row, 2 if an existing row is updated, and 0 if an existing row is set to its current values. If you specify the CLIENT_FOUND_ROWS flag to the mysql_real_connect() C API function when connecting to mysqld, the affected-rows value is 1 (not 0) if an existing row is set to its current values.

-- https://dev.mysql.com/doc/refman/5.6/en/insert-on-duplicate.html

like image 65
Rick James Avatar answered Sep 19 '22 01:09

Rick James


This is an interesting thing that I found recently too in MySQL 5.7. If you purposely try to insert a row that already exists using on duplicate key update, this query will also duplicate the number of rows affected.

For instance, run these queries:

CREATE TABLE int_0 (
 id INT NOT NULL AUTO_INCREMENT,
 VALUE INT DEFAULT 0,
 PRIMARY KEY (id) 
);

INSERT INTO int_0 VALUES(1, NULL) ON DUPLICATE KEY UPDATE VALUE = NULL;

Then run this:

INSERT INTO int_0 VALUES(1, 2) ON DUPLICATE KEY UPDATE VALUE = 2;

This query will show '2 rows affected' even though there is only 1 row in the table and affecting 2 rows is therefore impossible.

My theory is that it is trying to count the number of rows affected by the insert and the update, then adding them together. Somehow the ON DUPLICATE KEY UPDATE being triggered is getting counted as a row being 'affected' by the insert. I believe this is the behavior that you are seeing.

like image 25
drakin8564 Avatar answered Sep 20 '22 01:09

drakin8564