I'm doing a INSERT ... ON DUPLICATE KEY UPDATE
but I need the update part to be conditional, only doing the update if some extra condition has changed.
However, WHERE
is not allowed on this UPDATE
. Is there any workaround for this?
I can't do combinations of INSERT/UPDATE/SELECT since this needs to work over a replication.
I suggest you to use IF() to do that.
Refer: conditional-duplicate-key-updates-with-mysql
INSERT INTO daily_events (created_on, last_event_id, last_event_created_at)
VALUES ('2010-01-19', 23, '2010-01-19 10:23:11')
ON DUPLICATE KEY UPDATE
last_event_id = IF(last_event_created_at < VALUES(last_event_created_at), VALUES(last_event_id), last_event_id);
This is our final solution, works like a charm!
The insert ignore will make sure that the row exists on both the master and slave, in case they've ever diverted.
The update ... where makes sure that only the most recent update, globally, is the end result after all replication is done.
mysql> desc test;
+-------+--------------+------+-----+-------------------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+-------------------+-------+
| id | int(11) | NO | PRI | NULL | |
| value | varchar(255) | YES | | NULL | |
| ts | timestamp | NO | | CURRENT_TIMESTAMP | |
+-------+--------------+------+-----+-------------------+-------+
mysql> insert ignore into test values (4, "foo", now());
mysql> update test set value = "foo", ts = now() where id = 4 and ts <= now();
you could use two insert statements .. since you CAN add a where clause to the select part for the source data.
select two sets of data, one that you will insert with 'on duplicate' and the other will be inserted without 'on duplicate'.
table php_lock
:
name
:idString, locked
:bool,
time
:timestamp, locked_by
:string
values to insert or
update
1, CURRENT_TIMESTAMP, 'script'
where name
='wwww' AND
locked
=2
INSERT INTO `php_lock` (`name`, locked, `time`, `locked_by`)
(SELECT * FROM
(SELECT `name`,1,CURRENT_TIMESTAMP, 'script' FROM `php_lock`
WHERE `name`='wwww' AND `locked`=2
UNION (
SELECT 'wwww',1 ,CURRENT_TIMESTAMP, 'script')
) AS temp LIMIT 1)
ON DUPLICATE KEY UPDATE locked=VALUES(locked), `time`=VALUES(`time`), `locked_by`=VALUES(`locked_by`);
On duplicate key
do not allow us to use where clause, so there are two alternative to achieve the same.
If you know most of the time you will get the duplicate key then
a. Update the table first using update query and where clause
b. If update fails then insert the record into table using insert query
If you know most of the time you are going to insert into table then
a. Insert the record into table using insert ignore query - what it does is actually ignore the insert if duplicate key found
b. If insert ignore fails then update the record using update query
For reference of insert ignore
click here