Detect if MySQL has duplicates when inserting - mysql

I have a table with the columns value1, value2 and value3.
Every few months, all rows will need to change their 'value1' to a different value. So far I have the following code and I cannot figure out for the life of me why it is not working. Instead of only modifying column one, it generates an entire new row of information.
Thanks in advance.
INSERT INTO table (value1, value2, value3)
VALUES ('$valueForValue1', '$valueForValue2','$valueForValue3')
ON DUPLICATE KEY UPDATE
`value1`='$valueForValue1',
`value2`='$valueForValue2',
`value3`='$valueForValue3',

In order to be able to change a value of value1 with ON DUPLICATE KEY clause you have to have either a UNIQUE constraint or a PRIMARY KEY on (value2, value3).
ALTER TABLE table1 ADD UNIQUE (value2, value3);
Now to simplify your insert statement you can also use VALUES() in ON DUPLICATE KEY like this
INSERT INTO Table1 (`value1`, `value2`, `value3`)
VALUES ('$valueForValue1', '$valueForValue2', '$valueForValue3')
ON DUPLICATE KEY UPDATE value1 = VALUES(value1);
Here is SQLFIddle demo

The UPDATE action of the ON DUPLICATE KEY clause will only be executed if the row being inserted would cause the violation of a UNIQUE constraint. That means there needs to be a primary key or a unique index on the table.
If you want to modify existing rows, you'd really want to use an UPDATE statement.
To change the value in a column of existing rows, replacing 'oldvalue' with 'newvalue', you could do something like this:
UPDATE mytable
SET col1 = 'newvalue'
WHERE col1 = 'oldvalue'

Related

Referring to the current field value in the INSERT part of INSERT, ON DUPLICATE KEY UPDATE

When doing an INSERT statement with ON DUPLICATE KEY UPDATE is there a way to refer to the current value of a row and field, when it exists, in the VALUES part of the insert statement? I don't want to refer to it in the ON DUPLICATE KEY UPDATE section.
In my use case, all rows will always exist.
Something like this
INSERT INTO myTable (Col1, Col2) VALUES
('value', myTable.Col2),
('value2', myTable.Col2)
ON DUPLICATE KEY UPDATE
…
I tried this and it nulled all the columns in testing, probably because the reference failed and it returned null instead.
It may be germane to remark that I am trying to do this as part of adding an IF function to an INSERT, ON DUPLICATE KEY UPDATE query with prepared placeholders. So the final version will be like this:
INSERT INTO myTable (Col1, Col2) VALUES
('value', IF(?='test', myTable.Col2, ?),
('value2', myTable.Col2)
ON DUPLICATE KEY UPDATE
…
You can't refer to the current value of the row in the VALUES clause of an INSERT. You'll have to refer to the current value of the row in the ON DUPLICATE UPDATE clause.
For example, you could set the value to NULL in the values clause if your input
INSERT INTO myTable (Col1, Col2) VALUES
('value', NULLIF(?, 'test')), -- default to current value if you insert 'test'
('value2', NULL) -- default to current value always
ON DUPLICATE KEY UPDATE
Col2 = COALESCE(Col2, VALUES(Col2));

MySQL: How To Add IF EXISTS Then UPDATE Else INSERT? [duplicate]

UPDATE AggregatedData SET datenum="734152.979166667",
Timestamp="2010-01-14 23:30:00.000" WHERE datenum="734152.979166667";
It works if the datenum exists, but I want to insert this data as a new row if the datenum does not exist.
UPDATE
the datenum is unique but that's not the primary key
Jai is correct that you should use INSERT ... ON DUPLICATE KEY UPDATE.
Note that you do not need to include datenum in the update clause since it's the unique key, so it should not change. You do need to include all of the other columns from your table. You can use the VALUES() function to make sure the proper values are used when updating the other columns.
Here is your update re-written using the proper INSERT ... ON DUPLICATE KEY UPDATE syntax for MySQL:
INSERT INTO AggregatedData (datenum,Timestamp)
VALUES ("734152.979166667","2010-01-14 23:30:00.000")
ON DUPLICATE KEY UPDATE
Timestamp=VALUES(Timestamp)
Try using this:
If you specify ON DUPLICATE KEY UPDATE, and a row is inserted that would cause a duplicate value in a UNIQUE index orPRIMARY KEY, MySQL performs an [UPDATE`](http://dev.mysql.com/doc/refman/5.7/en/update.html) of the old row...
The ON DUPLICATE KEY UPDATE clause can contain multiple column assignments, separated by commas.
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 mysql_real_connect() when connecting to mysqld, the affected-rows value is 1 (not 0) if an existing row is set to its current values...
This is not too bad, but we could actually combine everything into one query. I found different solutions on the internet. The simplest, but MySQL only solution is this:
INSERT INTO wp_postmeta (post_id, meta_key)
SELECT
?id,
‘page_title’
FROM
DUAL
WHERE
NOT EXISTS (
SELECT
meta_id
FROM
wp_postmeta
WHERE
post_id = ?id
AND meta_key = ‘page_title’
);
UPDATE
wp_postmeta
SET
meta_value = ?page_title
WHERE
post_id = ?id
AND meta_key = ‘page_title’;
Link to documentation.
I had a situation where I needed to update or insert on a table according to two fields (both foreign keys) on which I couldn't set a UNIQUE constraint (so INSERT ... ON DUPLICATE KEY UPDATE won't work). Here's what I ended up using:
replace into last_recogs (id, hasher_id, hash_id, last_recog)
select l.* from
(select id, hasher_id, hash_id, [new_value] from last_recogs
where hasher_id in (select id from hashers where name=[hasher_name])
and hash_id in (select id from hashes where name=[hash_name])
union
select 0, m.id, h.id, [new_value]
from hashers m cross join hashes h
where m.name=[hasher_name]
and h.name=[hash_name]) l
limit 1;
This example is cribbed from one of my databases, with the input parameters (two names and a number) replaced with [hasher_name], [hash_name], and [new_value]. The nested SELECT...LIMIT 1 pulls the first of either the existing record or a new record (last_recogs.id is an autoincrement primary key) and uses that as the value input into the REPLACE INTO.

MYSQL to UPDATE table if row with 2 specific columns exist or INSERT new row if it does not exist

I have a MYSQL table that looks as follows:
id id_jugador id_partido team1 team2
1 2 1 5 2
2 2 2 1 1
3 1 2 0 0
I need to create a query to either INSERT new rows in the table or UPDATE the table. The condition is based on id_jugador and id_partido, meaning that if I wanted to insert id_jugador = 2 and id_partido = 1, then it should just UPDATE the existing row with the new team1 and team2 values I am sending. And dont duplicate the row.
However, if I have an entry id_jugador=2 and id_partido=3, since this combination does not exist yet, it should add the new row.
I read about the REPLACE INTO but it seems to be unable to check combination of UNIQUE KEYS.
If you have a UNIQUE KEY defined on the two columns (id_jugador, id_partido), then you can use:
INSERT ... ON DUPLICATE KEY ...
e.g.
INSERT INTO mytable (id_jugador, id_partido, team1, team2)
VALUES (?, ?, ?, ?)
ON DUPLICATE KEY
UPDATE team1 = VALUES(team1)
, team2 = VALUES(team2)
(Obviously, I'm assuming id is an AUTO_INCREMENT PRIMARY KEY, or there's a BEFORE INSERT trigger that generates a value for id when it's not provided.)
MySQL will attempt the INSERT (using up an auto_increment id value). If the INSERT succeeds, MySQL is done, it's just a regular insert. But if the INSERT throws a DUPLICATE KEY exception, then MySQL will perform an update action, equivalent to:
UPDATE mytable SET team1 = ?, team2 = ? WHERE id_jugador = ? AND id_partido = ?
Note that there can be multiple UNIQUE KEY constraints defined on a table. For the predicates of the UPDATE action, MySQL will use the columns/values of whichever unique (or primary) key is identified in the DUPLICATE KEY exception.
Also note that MySQL does actually attempt the INSERT, so MySQL does use up an AUTO_INCREMENT value, even when the INSERT throws a DUPLICATE KEY exception.
I normally avoid a REPLACE, because I usually have a lot of foreign keys, and I don't want a DELETE action. The DELETE action performed by REPLACE is a "real" DELETE; if there are foreign key references, the DELETE rule associated with the foreign key will be obeyed... the delete will fail if the DELETE rule is RESTRICT or NO ACTION and referencing rows exist, or if the DELETE rule is CASCADE or SET NULL, the referencing rows will be deleted or updated. I also believe any BEFORE/AFTER DELETE triggers will also be fired.
Apart from those options, you'd have to run two separate statements.
When I've needed to avoid an INSERT without having a UNIQUE KEY defined, I will typically do something like:
INSERT INTO mytable (id_jugador, id_partido, team1, team2)
SELECT i.*
FROM (SELECT ? AS id_jugador, ? AS id_partido, ? AS team1, ? AS team2) i
LEFT
JOIN mytable s
ON s.id_jugador <=> i.id_jugador
AND s.id_partido <=> i.id_partido
WHERE s.id IS NOT NULL
After the statement executes, test the number of affected rows. If it's zero, we know that the row was not inserted, so we can proceed with an UPDATE.

How to make insert or delete?

Structure table:
id (int primary key)
name (varchar 100)
date(datetime)
For insert I use query:
INSERT INTO table (name, date) VALUES ('t1','$date');
For delete row I use query:
DELETE FROM table WHERE name = 't1';
I would like want how make 1 query: first insert, if row with it name already exist, than delete row, and insert again.
Tell me please how to make it?
Create a UNIQUE index over your name column:
ALTER TABLE `table` ADD UNIQUE (name);
If you genuinely want to "delete row and insert again", then you can use REPLACE instead of INSERT. As documented:
REPLACE works exactly like INSERT, except that if an old row in the table has the same value as a new row for a PRIMARY KEY or a UNIQUE index, the old row is deleted before the new row is inserted.
Therefore, in your case:
REPLACE INTO `table` (name, date) VALUES ('t1','$date');
However, if instead of deleting the existing record and then inserting a new one you merely want to update the existing record, you can use INSERT ... ON DUPLICATE KEY UPDATE:
INSERT INTO `table` (name, date) VALUES ('t1','$date')
ON DUPLICATE KEY UPDATE date = VALUES(date);
The most material difference is in the treatment of columns for which you do not provide explicit values (such as id in your example): REPLACE will result in the new record having the default value, whereas INSERT ... ON DUPLICATE KEY UPDATE will result in the old value being retained.
What you want to do is use MySQL's on duplicate update feature.
Can be used like this :
INSERT INTO table (name, date) VALUES ('t1','$date')
ON DUPLICATE KEY UPDATE name=VALUES(name),dateVALUES(date);
Of course for that to happen a dupliate violation must occur.
insert into table (name, date) values('t1','$date') on duplicate key update name=values(name), date=values(date)
Are you looking for an update query?
Update will set a value on an already existing row.
UPDATE table SET date = '$newdate' WHERE name = 't1';
The best way to do this is using the mysql methods together with your query.
If you make the 'name' field unique:
id (int primary key)
name (varchar 100) NOT NULL UNIQUE
date(datetime)
And alter the query to:
INSERT INTO table
(name, date) VALUES ('t1','$date')
ON DUPLICATE KEY UPDATE date = "$date"

MySql Table Insert if not exist otherwise update

UPDATE AggregatedData SET datenum="734152.979166667",
Timestamp="2010-01-14 23:30:00.000" WHERE datenum="734152.979166667";
It works if the datenum exists, but I want to insert this data as a new row if the datenum does not exist.
UPDATE
the datenum is unique but that's not the primary key
Jai is correct that you should use INSERT ... ON DUPLICATE KEY UPDATE.
Note that you do not need to include datenum in the update clause since it's the unique key, so it should not change. You do need to include all of the other columns from your table. You can use the VALUES() function to make sure the proper values are used when updating the other columns.
Here is your update re-written using the proper INSERT ... ON DUPLICATE KEY UPDATE syntax for MySQL:
INSERT INTO AggregatedData (datenum,Timestamp)
VALUES ("734152.979166667","2010-01-14 23:30:00.000")
ON DUPLICATE KEY UPDATE
Timestamp=VALUES(Timestamp)
Try using this:
If you specify ON DUPLICATE KEY UPDATE, and a row is inserted that would cause a duplicate value in a UNIQUE index orPRIMARY KEY, MySQL performs an [UPDATE`](http://dev.mysql.com/doc/refman/5.7/en/update.html) of the old row...
The ON DUPLICATE KEY UPDATE clause can contain multiple column assignments, separated by commas.
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 mysql_real_connect() when connecting to mysqld, the affected-rows value is 1 (not 0) if an existing row is set to its current values...
This is not too bad, but we could actually combine everything into one query. I found different solutions on the internet. The simplest, but MySQL only solution is this:
INSERT INTO wp_postmeta (post_id, meta_key)
SELECT
?id,
‘page_title’
FROM
DUAL
WHERE
NOT EXISTS (
SELECT
meta_id
FROM
wp_postmeta
WHERE
post_id = ?id
AND meta_key = ‘page_title’
);
UPDATE
wp_postmeta
SET
meta_value = ?page_title
WHERE
post_id = ?id
AND meta_key = ‘page_title’;
Link to documentation.
I had a situation where I needed to update or insert on a table according to two fields (both foreign keys) on which I couldn't set a UNIQUE constraint (so INSERT ... ON DUPLICATE KEY UPDATE won't work). Here's what I ended up using:
replace into last_recogs (id, hasher_id, hash_id, last_recog)
select l.* from
(select id, hasher_id, hash_id, [new_value] from last_recogs
where hasher_id in (select id from hashers where name=[hasher_name])
and hash_id in (select id from hashes where name=[hash_name])
union
select 0, m.id, h.id, [new_value]
from hashers m cross join hashes h
where m.name=[hasher_name]
and h.name=[hash_name]) l
limit 1;
This example is cribbed from one of my databases, with the input parameters (two names and a number) replaced with [hasher_name], [hash_name], and [new_value]. The nested SELECT...LIMIT 1 pulls the first of either the existing record or a new record (last_recogs.id is an autoincrement primary key) and uses that as the value input into the REPLACE INTO.