MySQL on duplicate key update is not updating - mysql

I'm trying to use on duplicate key update but it's not affecting any rows.
My table create statement, where you can see that I've created a unique key on childid and date.
CREATE TABLE `history_childfees` (
`childid` int(11) DEFAULT NULL,
`date` date DEFAULT NULL,
`amount` decimal(10,2) DEFAULT NULL,
`feetypecode` varchar(45) DEFAULT NULL,
UNIQUE KEY `key_childdate` (`childid`,`date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
These are the two rows I have in the table.
The row I'm trying to update is the first row, by changing the amount for child 86615 on 2019-03-22.
insert into history_childfees (childid,date,amount,feetypecode)
values(86615,'2019-03-22',50,'DAY')
on duplicate key update childid = 86615, date = '2019-03-22';
I've also tried this syntax.
insert into history_childfees (childid,date,amount,feetypecode)
values (86615,'2019-03-22',50,'DAY')
on duplicate key update childid = values(childid), date = values(date);
Either way, it does not perform an insert and there's no error when I execute but it affects 0 rows. What am I missing here?

Consider:
CREATE TABLE `history_childfees` (
...
UNIQUE KEY `key_childdate` (`childid`,`date`)
);
And:
insert into history_childfees
...
on duplicate key update childid = 86615, date = '2019-03-22'
The columns that you update on duplicate key are exactly those of the UNIQUE KEY that you are using to identify duplicates. By design, we already know that the values do match... As a consequence, the query leaves duplicate records unmodified.
If I followed you correctly, you probably want:
insert into history_childfees
...
on duplicate key update amount = 50

Related

How to suppress unique key checking while sql insert

I got a MySQL database with some tables.
In one of these tables i want to insert by a SQL script some new rows.
Unfortunately i have to insert in two columns an empty string and the two columns are part of an unique key for that table.
So i tried to set UNIQUE_CHECKS before and after the insert, but i'm getting errors because of duplicate entries.
Here is the definition of the table:
CREATE TABLE `Table_A` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL,
`number` varchar(25) DEFAULT NULL,
`changedBy` varchar(150) DEFAULT NULL,
`changeDate` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`,`number`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
And the INSERT statement which causes error:
SET UNIQUE_CHECKS = 0;
INSERT INTO `Table_A`
(`name`, `number`, `changedBy`, `changeDate`)
SELECT DISTINCT '', 'myUser', CURRENT_TIMESTAMP
FROM Table_A
AND id NOT IN
(
SELECT DISTINCT id
FROM Table_A
);
SET UNIQUE_CHECKS = 1;
As You can see, i'm using UNIQUE_CHECKS.
But as i said this doesn't work properly.
Any help or suggestion would be appreciated.
Patrick
Switching off Unique Keys for the insert operation doesn't indicate that it will check uniqueness only for the operations that happen after you switch it on again. It just means that database will not waste time to check the constraint during the time it is switch off but it will check the constraint when you switch it on again.
What it measn is that you nead to ensure that column has unique value in a columns with Unique Keys before you can turn it on. Which you don't do.
If you want to maintain Uniqueness somehow for new records you insert after some point in time you would need to create trigger and manually check the new records against already existing data. The same possibly goes for updates. But I don't recommend it - you should probably redesign data so either the Unique Key is not there or the data is truly unique for all the records there are and will be.

Why does this SQL "UPSERT" affect two rows?

I was trying to write an upsert, and when I run these two queries sequentially:
// The numbers here are arbitrary, but id matches one already existing in db.
SET #id = 1069, #exportid = null, #photoid = 11223344;
INSERT INTO student (id_number, exportid, photoid) VALUES (#id, #exportid, #photoid)
ON DUPLICATE KEY UPDATE exportid = #exportid, photoid = #photoid;
and it hits the update and makes some changes, I get "2 rows affected". Why isn't it just one (If it hits the insert I get 1 row affected as expected)?
The CREATE statement for the table, with a bunch of non-key columns redacted:
CREATE TABLE `demo`.`student` (
`id_number` varchar(15) NOT NULL DEFAULT '',
`exportid` varchar(20) DEFAULT NULL,
`photoid` varchar(25) DEFAULT NULL,
PRIMARY KEY (`id_number`),
KEY `EXPORTID` (`exportid`),
KEY `NAME` (`last_name`,`student`,`id_number`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
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.
from the official docs

Is it possible to update only a single field with ON DUPLICATE KEY UPDATE in a table with multiple fields?

Is it possible to update only a single field with ON DUPLICATE KEY UPDATE in a table with multiple fields?
If I have a table with three fields; key, cats, dogs where key is the primary key is it possible to update a record on duplicate key, changing only one field, (for my example cats) without changing the value in the other non-key fields (dogs). This is without knowing what the value of dogs from outside of the database at the time of insertion (i.e. I have a variable holding cats value, but not one holding dogs value)
INSERT INTO `myTable` (`key`,`cats`) VALUES('someKey1','Manx') ON DUPLICATE KEY UPDATE `cats` = 'Manx';
At the moment when I run something like this and the key already exists in the table dogs is set to NULL even when it had a value previously.
Gordon is right, it does not work the way I described. If you see this, it is not caused by the ON DUPLICATE UPDATE statement, but something else. Here is the proof:
CREATE TABLE IF NOT EXISTS `myTable` (
`key` varchar(20) NOT NULL default '',
`cats` varchar(20) default NULL,
`dogs` varchar(20) default NULL,
PRIMARY KEY (`key`)
)
The run
INSERT INTO `myTable` (`key`, `cats`, `dogs`) VALUES
('someKey1', NULL, 'jack-russell');
Then run
INSERT INTO `myTable` (`key`,`cats`) VALUES
('someKey1','Manx') ON DUPLICATE KEY UPDATE `cats` = 'manx';
Then check the table
I think you should try to UPSERT.
Please examine this:
INSERT INTO `item` (`item_name`, items_in_stock) VALUES( 'A', 27)
ON DUPLICATE KEY UPDATE `new_items_count` = `new_items_count` + 27
MySQL UPSERT

auto-increment value in update conflicts with internally generated values

I've been getting this error from an insert on duplicate update query in MYSQL randomly every now and then.
Any idea what's going on? I can't seem to reproduce the error consistently it occurs sometimes and then sometimes not.
Here is the query in question:
INSERT INTO friendships (u_id_1,u_id_2,status) VALUES (?,?,'active') ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id);
And the schema describing the table is:
DROP TABLE IF EXISTS `friendships`;
CREATE TABLE `friendships` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`u_id_1` int(11) NOT NULL,
`u_id_2` int(11) NOT NULL,
`status` enum('active','pending','rejected','blocked') DEFAULT 'pending' NOT NULL,
`initiatiator` enum('1','2','system') DEFAULT 'system' NOT NULL,
`terminator` enum('1','2','system') DEFAULT NULL,
`confirm_timestamp` timestamp DEFAULT NULL,
`created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY (`u_id_1`,`u_id_2`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
Your ON DUPLICATE KEY UPDATE statement isn't helping you at all here.
You are taking the LAST_INSERT_ID, which is the auto inc of the last successfully inserted row, and trying to update the duplicated row with that id. This will always cause a duplicate primary (you're trying to change the id of some row to match the id of the last thing you added)
If your goal is to either
Insert a new row, or
Update an existing row with 'active'
Then
INSERT INTO friendships (u_id_1,u_id_2,status)
VALUES ( ? , ? ,'active')
ON DUPLICATE KEY UPDATE
status = 'active'; -- I changed this
A separate consideration is to check the source for duplicates. I had a simple audit table
INSERT INTO table
field1, field2, ... , field3
ON DUPLICATE KEY UPDATE row_id=row_id;
where field1 is an INDEX but not UNIQUE with row_ID as INTEGER UNSIGNED AUTO_INCREMENT PRIMARY KEY.
Ran for years, but an unexpected duplicate row triggered this error.
Fixed by de-duping the source.
Possibly a trivial point to many readers here, but it cost me some head-scratching (followed by a facepalm).

Mysql Deadlock in SELECT.. if nothing exists INSERT

I have a simple split testing table:
CREATE TABLE `tracked_split_test_track_variant` (
 `tracked_split_test_id` int(10) unsigned NOT NULL,
 `track_id` bigint(20) unsigned NOT NULL,
 `variant` char(1) NOT NULL,  
PRIMARY KEY (`tracked_split_test_id`,`track_id`),
 KEY `tracked_split_test_track_variant_1` (`tracked_split_test_id`),
 KEY `tracked_split_test_track_variant_2` (`track_id`),
 CONSTRAINT `fk_tracked_split_test_track_variant_2`
FOREIGN KEY (`track_id`)
REFERENCES `track` (`id`)
ON DELETE CASCADE ON UPDATE CASCADE,
 CONSTRAINT `fk_tracked_split_test_track_variant_1`
FOREIGN KEY (`tracked_split_test_id`)
REFERENCES `tracked_split_test` (`id`)
ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Where variant is a randomly A or B.
When the system asks 'Which variant should I show this user?' I want the following things to happen:
SELECT the tracked_split_test_track_variant that belongs to the current track and tracked_split_test
If no record exists create a new one with a random variant and INSERT it
Currently I'm running the SELECT and (optional) INSERT query in a transaction as:
SELECT *
FROM tracked_split_test_track_variant
WHERE track_id = :track_id
AND tracked_split_test_id = :tracked_split_test_id
FOR UPDATE
and
INSERT
INTO tracked_split_test_track_variant
VALUES (:track_id, :tracked_split_test_id, :variant)
I added the FOR UPDATE to the SELECT so that if two transactions were running with the same details.. I wouldn't get two INSERT attempts.
Even though I commit as soon as possible, I'm now getting deadlocks instead. Have I done this all wrong?
As the tuples are immutable outside of this transaction, I have come up with the following solution using explicit named locks:
SELECT GET_LOCK('tracked_split_test_track_variant-xxx-yyy',30);
SELECT *
FROM tracked_split_test_track_variant
WHERE tracked_split_test_id = :tracked_split_test_id
AND track_id = :track_id
[
INSERT
INTO tracked_split_test_track_variant
VALUES (:track_id, :tracked_split_test_id, :variant)
]
DO RELEASE_LOCK('tracked_split_test_track_variant-xxx-yyy');
Where xxx is the tracked_split_test_id and yyy is the track_id
I would be interested to see if there is a better solution out there however.