Update if one of the values exist, else insert - mysql

How can I at an insert query, check if a specific column has a specific value and then update the row. Otherwise it should insert a new row.
Somethings like this is what I want:
INSERT INTO table (col1, col2, col3) VALUES (val1, val2, val3) UPDATE IF col3 = $number

Create a UNIQUE key over your col3:
ALTER TABLE `table` ADD UNIQUE KEY (col3)
Then use INSERT ... ON DUPLICATE KEY UPDATE:
INSERT INTO `table` (col1, col2, col3) VALUES (val1, val2, val3)
ON DUPLICATE KEY UPDATE col1 = VALUES(col1), col2 = VALUES(col2)

Have a look at the REPLACE INTO command (MySQL docu).
REPLACE INTO table (col1, col2, col3) VALUES (val1, val2, val3);
It checks primary keys and unique indexes and when there is a matching entry already present, that row is replaced by the new one, else a new row is inserted.
EDIT
As #eggyal mentioned this the behaviour in the case, when the row is replaced, is actually a deletion of the old row and insertion of the new row afterwards. This may lead to some problems, when you're using triggers, foreign keys or alike.
Actually you might loose the content of some columns as well. Suppose you have a table with 3 columns (col1 to col3), but the REPLACE just sets two of them (col1, col2), the third one col3 will receive the default value specified and not retain the old value.

if you have unique index on that column then use this
INSERT INTO table (col1, col2, col3) VALUES (val1, val2, val3)
ON DUPLICATE KEY UPDATE col3 = $number

Related

UPSERT with non-unique index

I need to implement concurrent-safe UPSERT using a non-unique key and avoid unnecessary auto-increment of ID.
Traditional INSERT ... ON DUPLICATE KEY doesn't work for me, so I'm performing:
INSERT INTO table (col1, col2, col3, col4, col5)
SELECT 1, 2, 'value3', 'value4', 'value5'
WHERE NOT EXISTS (SELECT 1
FROM table
WHERE col3 = 'value3'
AND col4 = 'value4'
AND col5 = 'value5')
then if it results in no row inserted, I'm performing:
UPDATE table
SET col1 = col1 + 1,
col2 = MAX(col2, 2)
WHERE col3 = 'value3'
AND col4 = 'value4'
AND col5 = 'value5'
There's an index:
CREATE INDEX ON table (col3, col4, col5)
It is non-unique as there are legacy data that does not allow me to declare it unique. Newer records, however, should not have duplicated (col3, col4, col5) rows.
Unsurprisingly, using the given INSERT statement I'm getting mixed results trying to execute it concurrently from two sessions. I can see the second session blocking until the first one commits its transaction, but then the second transaction is also able to insert a new row sometimes (or sometimes it achieves the expected of avoiding to insert a duplicate (col3, col4, col5) row).
I'm currently performing manual unique-check after the insert:
SELECT COUNT(1)
FROM table
WHERE col3 = 'value3'
AND col4 = 'value4'
AND col5 = 'value5'
but I've also tried:
INSERT INTO table (col1, col2, col3, col4, col5)
SELECT 1, 2, 'value3', 'value4', 'value5'
WHERE NOT EXISTS (SELECT 1
FROM table
WHERE col3 = 'value3'
AND col4 = 'value4'
AND col5 = 'value5'
FOR UPDATE)
which appears to work with the examples I'm always getting a duplicate (col3, col4, col5) row, otherwise. Is the given FOR UPDATE usage reliable for the purpose of ensuring no duplicate (col3, col4, col5) row will be inserted?
I'm using READ-COMMITTED transaction isolation.
MySQL 8.0.13 and higher supports functional key parts that index expression values rather than column or column prefix values. (link)
Because you have a unique field, i am assuming this is col, you can add an index like:
CREATE unique INDEX idx2 ON `mytable` ((col1>42),col3, col4, col5);
Where 42 should be the next auto-increment for col1.
Newly create records will be unique on the 3 columns, without affecting your 'old' data.
It is even possible to update the old data (as long as col1<=42).

How to insert values into a table according to the index values of columns in MySQL database?

I want to add values according to index in my table.
This is the code I am trying right now.
insert into A(1,2) values ('ABC','CBA');
The insert statement does not accepts column indexes, but column names. Say your table called a has three columns called id, col1 and col2, and you want to insert into the last two columns, you would do:
insert into a (col1, col2) values('ABC', 'CBA');
The only way that you can add columns according to position is to leave out the column list and include all columns:
insert into A
values ('ABC', 'CBA');
That said, you really should be explicit about which columns are getting values, by including the column names:
insert into A (col1, col2)
values ('ABC', 'CBA');
Or using the MySQL set extension:
insert into A (col1, col2)
set col1 = 'ABC', col2 = 'CBA';

Update or insert mysql

I am trying to find a solution to update or insert value in my MySQL table (like in firebird you have UPDATE OR INSERT INTO TABLE (COL1, COL2, COL3) VALUES (VAL1, VAL2, VAL3) MATCHING (COL1, COL2).
I know MySQL have on duplicate key but I do not want that! I do not want to set a key on some of my columns because that one table is used depending on the situation.
So is there any other way of performing update or insert action?
if I remember correctly COL1 should be unique
INSERT INTO table
(COL1, COL2, COL3)
VALUES
(?, ?, ?)
ON DUPLICATE KEY UPDATE
COL2 = VALUES(COL2)
COL2 = VALUES(COL2 )

SQL insert list of values in one column dynamicallly

I would like to execute a insert query once for inserting multiple list of records in one column
INSERT INTO Table (col1, col2, col3)
VALUES (val1, val2, listVal3);
The third column only is the list
listVal3 is a list of ids from request
Is it possible to execute to a query like above to insert multiple records
in one column dynamically, if so please help me, thanks.
Maybe you want to create several records having the same values in the first two columns and taking the third column values from table request? In that case the following statement might be useful:
INSERT INTO Table (col1, col2, col3)
SELECT 'val1', 'val2', id from request
WHERE ... --- (some conditions)
You can concat the listVal3 values.
INSERT INTO `tmp_tbl2` (col1, col2, col3)
VALUES (val1, val2, (SELECT GROUP_CONCAT(id) FROM request WHERE ....))

How to know if when using "on duplicate key update" a row was inserted or updated?

We have a database that gets updated everyday at midnight with a cronjob, we get new data from an external XML.
What we do is that we insert all the new content and in case there is a duplicated key we update that field.
INSERT INTO table (id, col1, col2, col3)
values (id_value, val1, val2, val3),
(id_value, val1, val2, val3),
(id_value, val1, val2, val3),
(id_value, val1, val2, val3),
ON DUPLICATE KEY UPDATE
col1 = VALUES (col1),
col2 = VALUES (col2),
col3 = VALUES (col3);
What we want to know is which rows have actually been inserted, meaning we want to have a list of the new items. is there any query that might return the new inserts? Basically we will need to get all the new ID's and not the number of new insertions.
Thanks
You can get this information at the time of the insert/update by examining the number of affected rows in the result set.
MySQL documentation states:
With ON DUPLICATE KEY UPDATE, the affected-rows value per row is 1 if
the row is inserted as a new row and 2 if an existing row is updated.
You'll need to combine ROW_COUNT with LAST_INSERT_ID to get your answer and insert one row at a time.
Add an update_count INT NOT NULL DEFAULT 1 column and change your query:
INSERT
INTO table (id, col1, col2, col3)
VALUES
(id_value, val1, val2, val3),
(id_value, val1, val2, val3,),
(id_value, val1, val2, val3),
(id_value, val1, val2, val3),
ON DUPLICATE KEY
UPDATE
col1 = VALUES (col1),
col2 = VALUES (col2),
col3 = VALUES (col3),
update_count = update_count + 1;
You can also increment it in a BEFORE UPDATE trigger which will allow you to keep the query as is.
I can say How I did in PHP:
1) Simple query SELECT MAX(id) and remember it to $max_id from table before Insert On Duplicate.
2) Then during the update process collect ID of affected rows (no mater new or existed): $ids[] = mysql_insert_id();
3) Then $inserted_rows = max($ids)-$max_id;
4) Updated rows = count($ids_srt)-$inserted_rows
$max_id = mysql_query("SELECT MAX(id) from table");
$max_id = mysql_result($max_id, 0);
// !!! prepare here 'insert on duplicate' query in a cycle
$result=mysql_query($query);
$ids[] = mysql_insert_id();
// finish inserting and collecting affected ids and close cycle
$inserted_rows = max($ids)- $max_id;
$updated_rows = count($ids)- $inserted_rows