MySQL 'UPDATE ON DUPLICATE KEY' without a unique column? - mysql

What are peoples' thoughts on the most performance efficient way to do the following query:
3 column table
if the combination of col_1 and col_2 values already exist UPDATE col_3
else INSERT new row
I assume i need some kind if UPDATE ON DUPLICATE KEY (which i've never used before), however I do not have a 'KEY' but instead a pair of two values (columns) to make a key...

You can create a PRIMARY or UNIQUE key out of multiple columns (called a composite key) in MySQL, which'll allow ON DUPLICATE KEY to work just fine.
// create a composite index
CREATE INDEX my_composite_index ON my_table (column1, column2);
// insert or update
INSERT INTO my_table (column1, column2) VALUES ('value1', 'value2') ON DUPLICATE KEY UPDATE column3=column3+1;

Most efficient way is to create UNIQUE KEY and use ON DUPLICATE KEY UPDATE.
Slower way is to:
LOCK TABLE
SELECT TABLE (you need an index anyway for the best performance)
if exists, UPDATE
else INSERT
UNLOCK TABLES

Edit: Ignore my suggestions
You can use a composite key as ceejayoz said, however I think you need REPLACE INTO instead of UPDATE ON DUPLICATE KEY because REPLACE also inserts if no duplicate is found.
Note: I don't know the workings of UPDATE ON DUPLICATE KEY but it sounds like it doesn't perform inserts.

Related

Ignore values on insert with ON DUPLICATE UPDATE

I have an Insert Statement like:
f"INSERT INTO `system_measurements`(`Global_irradiance_tilted_in_Wh_per_m2`, `a_id`, `subDate`) VALUES ('{temp}', '{temp_id}', '{i.date()}')"
And want it to ignore existing entries without checking the date everytime. So i thouhgt I could use
ON DUPLICATE KEY UPDATE a_id=a_id
But it still adds all values to the table.
I interpret your question as saying that a new row is inserted despite the on duplicate key.
In order for on duplicate key to work, you need a unique constraint or index. The update takes place when the query violates the unique constraint.
I am guessing that you want this on a_id, so be use you have something like:
alter table system_measurements add constraint unq_ system_measurements_a_id
unique (a_id);
INSERT IGNORE will do nothing other than discovering that it is a duplicate. "Duplicate" is checked via the PRIMARY KEY and any UNIQUE keys.
Simply stick IGNORE after INSERT in the SQL you have.

MySQL "Insert ... On Duplicate Key" with more than one unique key

I've been reading up on how to use MySQL insert on duplicate key to see if it will allow me to avoid Selecting a row, checking if it exists, and then either inserting or updating. As I've read the documentation however, there is one area that confuses me. This is what the documentation says:
If you specify ON DUPLICATE KEY UPDATE, and a row is inserted that would cause a duplicate value in a UNIQUE index or PRIMARY KEY, an UPDATE of the old row is performed
The thing is, I don't want to know if this will work for my problem, because the 'condition' I have for not inserting a new one is the existence of a row that has two columns equal to a certain value, not necessarily that the primary key is the same. Right now the syntax I'm imagining is this, but I don't know if it will always insert instead of replace:
INSERT INTO attendance (event_id, user_id, status) VALUES(some_event_number, some_user_id, some_status) ON DUPLICATE KEY UPDATE status=1
The thing is, event_id and user_id aren't primary keys, but if a row in the table 'attendance' already has those columns with those values, I just want to update it. Otherwise I would like to insert it. Is this even possible with ON DUPLICATE? If not, what other method might I use?
The quote includes "a duplicate value in a UNIQUE index". So, your values do not need to be the primary key:
create unique index attendance_eventid_userid on attendance(event_id, user_id);
Presumably, you want to update the existing record because you don't want duplicates. If you want duplicates sometimes, but not for this particular insert, then you will need another method.
If I were you, I would make a primary key out of event_id and user_id. That will make this extremely easy with ON DUPLICATE.
SQLFiddle
create table attendance (
event_id int,
user_id int,
status varchar(100),
primary key(event_id, user_id)
);
Then with ease:
insert into attendance (event_id, user_id, status) values(some_event_number, some_user_id, some_status)
on duplicate key
update status = values(status);
Maybe you can try to write a trigger that checks if the pair (event_id, user_id) exists in the table before inserting, and if it exists just update it.
To the broader question of "Will INSERT ... ON DUPLICATE respect a UK even if the PK changes", the answer is yes: SQLFiddle
In this SQLFiddle I insert a new record, with a new PK id, but its values would violate the UK. It performs the ON DUPLICATE and the original PK id is preserved, but the non-UK ON DUPLICATE KEY UPDATE value changes.

MYSQL: Getting existing primary key when inserting record with duplicate unique key?

I've got a mysql database with a table that has both a auto-increment primary key and unique string valued key (a sha-1 hash).
If I try to add a record that has the same sha-1 hash as an existing record, I just want to get the primary key of the existing record. I can use something like "INSERT ... ON DUPLICATE KEY UPDATE" or "INSERT IGNORE" to prevent an exception when trying to insert a record with a existing hash value.
However, when that happens, I need to retrieve the primary key of the existing record. I can't find a way to do that with a single SQL statement. If it matters, my code is in Java and I'm using JDBC.
Alternatively, I can do it with two statements (either a query followed by an insertion if not found, or a insertion followed by a query if a duplicate key exists). But I presume a single statement would be more efficient.
If I try to add a record that has the same sha-1 hash as an existing
record, I just want to get the primary key of the existing record. I
can use something like "INSERT ... ON DUPLICATE KEY UPDATE" or "INSERT
IGNORE" to prevent an exception when trying to insert a record with a
existing hash value.
If you have an UNIQUE index on a column, no matter what you tried, the RDMS will not allow duplicates in that column (except for the NULL value).
As you said, there is solution to prevent "error" if this appends. Probably INSERT IGNORE in your case.
Anyway, INSERT and UPDATE modify the database. MySQL never return values for these statements. The only way to read your DB is to use a SELECT statement.
Here the "workaround" is simple, since you have an UNIQUE column:
INSERT IGNORE INTO tbl (pk, sha_key) VALUES ( ... ), ( ... );
SELECT pk, sha_key FROM tbl WHERE sha_key IN ( ... );
-- ^^^
-- Here the list of the sha1 keys you *tried* to insert
Actually, INSERT...ON DUPLICATE KEY UPDATE is exactly the right statement to use in your situation. When you use ON DUPLICATE, if the insert happens without duplicate, JDBC returns count of 1 and the ID of the newly inserted row. If the action taken is an update due to duplicate, JDBC returns count of 2 and both the ID of the original row AND the newly generated ID, even though the new ID is never actually inserted into the table.
You can get the correct key by calling PreparedStatement.getGeneratedKeys(). The first key is pretty much always the one you are interested in. For this statement:
INSERT INTO table (a,b,c) VALUES (1,2,3) ON DUPLICATE KEY UPDATE c=3;
You can get the inserted or updated ID by calling:
Long key;
ResultSet keys = preparedStatement.getGeneratedKeys();
if (keys.next())
key = keys.getLong("GENERATED_KEY");

Prevent MySQL Duplicate Insert

I have a mysql table with a auto incremented key. I need a way to only insert into that table if the table does not contain the row I am inserting. INSERT IGNORE and INSERT ON DUPLICATE KEY UPDATE won't work because the auto incremented key will cause the row to always be different. What is another way I can insert the following line only if there is no duplicate row? Thanks.
INSERT INTO TableName (column1, column2, column3) VALUES ("value1", "value2", "value3");
Set a UNIQUE constraint on whichever column you need to be unique, or a combination of columns.
For example:
ALTER TABLE `TableName`
ADD UNIQUE `constrain_me` (`column1`, `column2`);
If you want to ignore any error a duplicate insert might give, use INSERT IGNORE, although you may want to catch this error instead of brushing it under the rug.
You can create Unique Indexes on the fields that you don't want duplicated.
CREATE UNIQUE INDEX MyIndex ON column1
This way, if a duplicate value is added, the query will error out. It's also worth noting that this method does allow NULL values to be added (i.e. two rows with NULL column1 values won't count as duplicates)

why the term key in on duplicate statements?

I am new to mysql and was reading about on duplicate key update. The statement we generally write would be something like this
insert into table (col1,col2) values(1,1) on duplicate key update col2=1;
Assuming col1 to be primary.
My understanding of this is statement is that if there is duplicate value in col1 the respective statement updates col2 with 1. My question is why do we use the term "key" in this statement? As it is understood that the statement updates only when there is a primary key violation. Are there any other parameters or function which we can use with duplicate?
Thanks
MySQL updates either if there is a primary or a unique key violation. The manual covers it quite extensively in a separate chapter with examples:
If you specify ON DUPLICATE KEY UPDATE, and a row is inserted that
would cause a duplicate value in a UNIQUE index or PRIMARY KEY, MySQL
performs an UPDATE of the old row.
The term key is used as part of the syntax definition. The term is afaik only available when performing INSERT-statements. If you insert data by any other means (I can only think of LOAD DATA right now), other mechanisms come into place.
There are no other options with this command. In additional I want to say that you can rewrite the statement in this way -
INSERT INTO table (col1, col2) VALUES(1, 1) ON DUPLICATE KEY UPDATE col2 = VALUES(col2);
Also you can use:
an INSERT statement with IGNORE keyword to ignore errors.
a REPLACE statement to replace records by unique key.
In other words INSERT+ON DUPLICATE KEY UPDATE works like an INSERT and REPLACE in one statement. And one more thing - the INSERT+ON DUPLICATE KEY UPDATE statement has big advantage, it does not remove records on updating; the REPLACE statement removes and then inserts new record.