I'm reading about conditional updates on duplicate key based on IF statements - e.g., MySQL Conditional Insert on Duplicate.
I'm trying to do something similar, but within an insert from a select:
INSERT IGNORE INTO data1 (id, date, quantity)
SELECT id, date, quantity
FROM other_table
WHERE date = '2015-03-01'
AND id=123
ON DUPLICATE KEY UPDATE
quantity = IF(quantity IS NULL, VALUES(quantity), quantity)
However, this generates an error:
#1052 - Column 'quantity' in field list is ambiguous
I can't quite figure out how to tell MySQL which 'quantity' field is which in order to resolve the ambiguity problem. Adding aliases to each table doesn't seem to help (calling data1 'd' throws a different error).
Anyone have experience with this?
You should qualify the references to the quantity field that belongs to table data1 in the ON DUPLICATE KEY UPDATE part of the query:
INSERT INTO data1 (id, date, quantity)
SELECT id, date, quantity
FROM other_table
WHERE date = '2015-03-01'
AND id=123
ON DUPLICATE KEY UPDATE
quantity = IF(data1.quantity IS NULL, VALUES(quantity), data1.quantity)
A shorter way to write this IF() expression is to use function IFNULL() or COALESCE():
ON DUPLICATE KEY UPDATE
quantity = IFNULL(data1.quantity, VALUES(quantity))
or
ON DUPLICATE KEY UPDATE
quantity = COALESCE(data1.quantity, VALUES(quantity))
Also, there is no need to use IGNORE. The errors that IGNORE converts to warnings does not happen any more because of the ON DUPLICATE KEY UPDATE clause.
mySQL doesn't know to which quantity collumn you are referring since it is present in both data1 and other_table tables.
You have to use it like this: other_table.quantity
Your query will change like this
INSERT IGNORE INTO data1 (id, date, quantity)
SELECT id, date, quantity
FROM other_table
WHERE date = '2015-03-01'
AND id=123
ON DUPLICATE KEY UPDATE
data1.quantity = IF(other_table.quantity IS NULL,
VALUES(other_table.quantity), other_table.quantity)
Related
I have a query that need to insert values in a table and update them if the key already exists.
This request is the following:
INSERT INTO table1(`id`, `day`, `quantity`, `residue`)
SELECT
id,
SUBDATE(NOW(), 1) as day,
(
A SUB QUERY
) as qte,
(
ANOTHER SUB QUERY
) as r
FROM table2
ON DUPLICATE KEY UPDATE
quantity=qte,
residue=r;
This request result in the error Unknown column 'qte' in 'field list'
What did I miss ?
You want VALUES():
ON DUPLICATE KEY UPDATE
quantity = VALUES(quantity),
residue = VALUES(residue)
How this works is explained in the documentation:
In assignment value expressions in the ON DUPLICATE KEY UPDATE clause, you can use the VALUES(col_name) function to refer to column values from the INSERT portion .
INSERT INTO policy_consent_status (patien_ID,policy_ID,PS_ID)
VALUES
((SELECT patient_ID FROM patient WHERE first_name="Christine"),(SELECT policy_ID
FROM policy WHERE policy_name="PI"),6)
ON DUPLICATE KEY
UPDATE
patien_ID = VALUES((SELECT patient_ID FROM patient WHERE first_name="Christine")),
policy_ID = VALUES((SELECT policy_ID FROM policy WHERE policy_name="PI"))
PS_ID = 6
I have to insert on new and update on existing
In ON DUPLICATE KEY UPDATE, the argument to VALUES has to be the name of a column; it returns the value that would have been inserted into the new row. If you want to use some other value, just put the expression there, without VALUES.
But you don't need multiple subqueries. Use a SELECT query as the source of the values to insert.
Also, you don't need to assign the values of the columns that are part of the unique key, only the columns that you want to update. I assume in your table the unique key is the combination of patient_id and policy_id.
INSERT INTO policy_consent_status (patient_ID,policy_ID,PS_ID)
SELECT patient_id, policy_id, 6
FROM patient
CROSS JOIN policy
WHERE first_name="Christine"
AND policy_name="PI"
ON DUPLICATE KEY UPDATE PS_ID = VALUES(PS_ID)
$sql = "INSERT IGNORE INTO product (reference, description, price, created_at, updated_at)
VALUES ('{$sku}', '{$description}', '{$price}', '{$created_at}', '{$updated_at}')";
.. keeps on creating new rows because of the incrementing id column, how do I make SKU unique so it checks if SKU value exists, then UPDATE instead of INSERT.
Add a unique key on the column you don't want to allow duplicates of:
ALTER TABLE product ADD UNIQUE KEY (reference);
Once you've done this, you can use the ON DUPLICATE KEY UPDATE clause to update the row instead of ignoring the INSERT.
INSERT INTO product (reference, description, price, created_at, updated_at)
VALUES ('{$sku}', '{$description}', '{$price}', '{$created_at}', '{$updated_at}')
ON DUPLICATE KEY UPDATE
description = VALUES(description),
price = VALUES(price),
created_at = VALUES(created_at),
updated_at = VALUES(updated_at)
Using VALUES in the ON DUPLICATE KEY clause picks up the values that would have been assigned during an INSERT of a new row.
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"
Using the answer from this question: Need MySQL INSERT - SELECT query for tables with millions of records
new_table
* date
* record_id (pk)
* data_field
INSERT INTO new_table (date,record_id,data_field)
SELECT date, record_id, data_field FROM old_table
ON DUPLICATE KEY UPDATE date=old_table.data, data_field=old_table.data_field;
I need this to work with a group by and join.. so to edit:
INSERT INTO new_table (date,record_id,data_field,value)
SELECT date, record_id, data_field, SUM(other_table.value) as value FROM old_table JOIN other_table USING(record_id) GROUP BY record_id
ON DUPLICATE KEY UPDATE date=old_table.data, data_field=old_table.data_field, value = value;
I can't seem to get the value updated. If I specify old_table.value I get a not defined in field list error.
Per the docs at http://dev.mysql.com/doc/refman/5.0/en/insert-select.html
In the values part of ON DUPLICATE KEY UPDATE, you can refer to columns in other tables, as long as you do not use GROUP BY in the SELECT part. One side effect is that you must qualify nonunique column names in the values part.
So, you cannot use the select query because it has a group by statement. You need to use this trick instead. Basically, this creates a derived table for you to query from. It may not be incredibly efficient, but it works.
INSERT INTO new_table (date,record_id,data_field,value)
SELECT date, record_id, data_field, value
FROM (
SELECT date, record_id, data_field, SUM(other_table.value) as value
FROM old_table
JOIN other_table
USING(record_id)
GROUP BY record_id
) real_query
ON DUPLICATE KEY
UPDATE date=real_query.date, data_field=real_query.data_field, value = real_query.value;
While searching around some more, I found a related question: "MySQL ON DUPLICATE KEY UPDATE with nullable column in unique key".
The answer is that VALUES() can be used to refer to column "value" in the select sub-query.