IF EXISTS THEN ELSE - mysql

It is pretty straight forward, but I could not find an answer. If the combination does exist, then UPDATE, else INSERT.
IF EXISTS(SELECT customer_id FROM payment_conditions WHERE customer_id = 2 AND shipping_company_id = 1)
THEN
UPDATE payment_conditions SET payment_condition = "pay in full" WHERE customer_id = 2 AND shipping_company_id = 1;
ELSE
INSERT INTO payment_conditions customer_id, shipping_company_id, payment_condition, active VALUES (2,1,"some value",1);
END IF

You should set customer_id and shipping_company_id to be foreign keys, so you can use
INSERT INTO payment_conditions
customer_id, shipping_company_id, payment_condition, active
VALUES (2, 1, "some value", 1)
ON DUPLICATE KEY UPDATE payment_condition = "pay in full"

if you have a unique key on (shipping_company_id, customer_id) you can use:
INSERT INTO payment_conditions
SET customer_id = 2,
shipping_company_id = 1,
payment_condition = 'some value',
active = 1
ON DUPLICATE KEY UPDATE payment_condition = 'pay in full'

INSERT INTO payment_conditions (customer_id, shipping_company_id, payment_condition, active)
VALUES (2,1,"some value",1)
ON DUPLICATE KEY UPDATE payment_condition = "pay in full"

Or issue two statements (N.B. with UPDATE first), and do away with the conditional logic. The UPDATE will have no effect if the row does not exist. This should work if your key happens to be different to the customer_id + shipping_company.
UPDATE payment_conditions SET payment_condition = "pay in full"
WHERE customer_id = 2 AND shipping_company_id = 1;
then
INSERT INTO payment_conditions
(customer_id
, shipping_company_id
, payment_condition
, active)
VALUES (2,1,"some value",1)
where not exists
(select * FROM payment_conditions
WHERE customer_id = 2 AND shipping_company_id = 1);

Use the merge statement in SQL Server - it looks like these answers imply MySQL syntax. You don't state the database flavor, but Merge is the recommended way to do this on SQL Server.

Related

Is it possible to use 'join' in INSERT ON DUPLICATE KEY UPDATE

I am trying to alter my code so when there is no row with a matching ean13 in webshop_stock it needs to INSERT a new row.
MYSQL is currently not accepting my code. i have tried a few things in order to get it working. My search on the worldwide-web did not find a good example with INSERT INTO - JOIN - ON DUPLICATE KEY UPDATE. So my question is, is it possible?
The problem at this moment is that my rows get created when they not exist, but the rows that exist does not get updated.
Tested the following code:
INSERT INTO webshop_stock
(id_warehouse,id_product,id_product_attribute,ean13, physical_quantity, usable_quantity)
SELECT
'1',
pa.id_product,
pa.id_product_attribute,
pa.ean13,
ai.quantity,
ai.quantity
FROM
webshop_product_attribute pa,
Adcount_input ai
WHERE
pa.ean13 = ai.ean13
AND NOT EXISTS
(SELECT id_product_attribute FROM webshop_stock
WHERE id_product_attribute = pa.id_product_attribute)
ON DUPLICATE KEY UPDATE
physical_quantity = ai.quantity,
usable_quantity = ai.quantity
Original code:
UPDATE
webshop_stock AS s
JOIN(
SELECT
pa.ean13,
pa.id_product_attribute,
pa.id_product,
ai.quantity
FROM
webshop_product_attribute pa,
Adcount_input ai
WHERE
pa.ean13=ai.ean13) q
SET
s.id_warehouse = 1,
s.id_product = q.id_product,
s.id_product_attribute = q.id_product_attribute,
s.ean13 = q.ean13,
s.physical_quantity = q.quantity,
s.usable_quantity = q.quantity
WHERE
s.id_product_attribute = q.id_product_attribute
SOLVED this code does what i need.
INSERT INTO webshop_stock
(id_warehouse, id_product, id_product_attribute, ean13, physical_quantity, usable_quantity)
SELECT
'1',
pa.id_product,
pa.id_product_attribute,
pa.ean13,
ai.quantity,
ai.quantity
FROM
webshop_product_attribute pa,
Adcount_input ai
WHERE
pa.ean13 = ai.ean13
ON DUPLICATE KEY UPDATE
physical_quantity = ai.quantity, usable_quantity = ai.quantity
The syntax is:
INSERT <table> <field list>
SELECT ... JOIN ...
There is NO INSERT JOIN SELECT in mysql. It's INSERT SELECT JOIN.
http://dev.mysql.com/doc/refman/5.1/en/insert-select.html

UPDATE multiple rows with different values in one query in MySQL

I am trying to understand how to UPDATE multiple rows with different values and I just don't get it. The solution is everywhere but to me it looks difficult to understand.
For instance, three updates into 1 query:
UPDATE table_users
SET cod_user = '622057'
, date = '12082014'
WHERE user_rol = 'student'
AND cod_office = '17389551';
UPDATE table_users
SET cod_user = '2913659'
, date = '12082014'
WHERE user_rol = 'assistant'
AND cod_office = '17389551';
UPDATE table_users
SET cod_user = '6160230'
, date = '12082014'
WHERE user_rol = 'admin'
AND cod_office = '17389551';
I read an example, but I really don't understand how to make the query. i.e:
UPDATE table_to_update
SET cod_user= IF(cod_office = '17389551','622057','2913659','6160230')
,date = IF(cod_office = '17389551','12082014')
WHERE ?? IN (??) ;
I'm not entirely clear how to do the query if there are multiple condition in the WHERE and in the IF condition..any ideas?
You can do it this way:
UPDATE table_users
SET cod_user = (case when user_role = 'student' then '622057'
when user_role = 'assistant' then '2913659'
when user_role = 'admin' then '6160230'
end),
date = '12082014'
WHERE user_role in ('student', 'assistant', 'admin') AND
cod_office = '17389551';
I don't understand your date format. Dates should be stored in the database using native date and time types.
MySQL allows a more readable way to combine multiple updates into a single query. This seems to better fit the scenario you describe, is much easier to read, and avoids those difficult-to-untangle multiple conditions.
INSERT INTO table_users (cod_user, date, user_rol, cod_office)
VALUES
('622057', '12082014', 'student', '17389551'),
('2913659', '12082014', 'assistant','17389551'),
('6160230', '12082014', 'admin', '17389551')
ON DUPLICATE KEY UPDATE
cod_user=VALUES(cod_user), date=VALUES(date)
This assumes that the user_rol, cod_office combination is a primary key. If only one of these is the primary key, then add the other field to the UPDATE list.
If neither of them is a primary key (that seems unlikely) then this approach will always create new records - probably not what is wanted.
However, this approach makes prepared statements easier to build and more concise.
UPDATE table_name
SET cod_user =
CASE
WHEN user_rol = 'student' THEN '622057'
WHEN user_rol = 'assistant' THEN '2913659'
WHEN user_rol = 'admin' THEN '6160230'
END, date = '12082014'
WHERE user_rol IN ('student','assistant','admin')
AND cod_office = '17389551';
You can use a CASE statement to handle multiple if/then scenarios:
UPDATE table_to_update
SET cod_user= CASE WHEN user_rol = 'student' THEN '622057'
WHEN user_rol = 'assistant' THEN '2913659'
WHEN user_rol = 'admin' THEN '6160230'
END
,date = '12082014'
WHERE user_rol IN ('student','assistant','admin')
AND cod_office = '17389551';
To Extend on #Trevedhek answer,
In case the update has to be done with non-unique keys, 4 queries will be need
NOTE: This is not transaction-safe
This can be done using a temp table.
Step 1: Create a temp table keys and the columns you want to update
CREATE TEMPORARY TABLE temp_table_users
(
cod_user varchar(50)
, date varchar(50)
, user_rol varchar(50)
, cod_office varchar(50)
) ENGINE=MEMORY
Step 2: Insert the values into the temp table
Step 3: Update the original table
UPDATE table_users t1
JOIN temp_table_users tt1 using(user_rol,cod_office)
SET
t1.cod_office = tt1.cod_office
t1.date = tt1.date
Step 4: Drop the temp table
In php, you use multi_query method of mysqli instance.
$sql = "SELECT COUNT(*) AS _num FROM test;
INSERT INTO test(id) VALUES (1);
SELECT COUNT(*) AS _num FROM test; ";
$mysqli->multi_query($sql);
comparing result to transaction, insert, case methods in update 30,000 raw.
Transaction: 5.5194580554962
Insert: 0.20669293403625
Case: 16.474853992462
Multi: 0.0412278175354
As you can see, multiple statements query is more efficient than the highest answer.
Just in case if you get error message like this:
PHP Warning: Error while sending SET_OPTION packet
You may need to increase the max_allowed_packet in mysql config file.
UPDATE Table1 SET col1= col2 FROM (SELECT col2, col3 FROM Table2) as newTbl WHERE col4= col3
Here col4 & col1 are in Table1. col2 & col3 are in Table2 I Am trying to update each col1 where col4 = col3 different value for each row
I did it this way:
<update id="updateSettings" parameterType="PushSettings">
<foreach collection="settings" item="setting">
UPDATE push_setting SET status = #{setting.status}
WHERE type = #{setting.type} AND user_id = #{userId};
</foreach>
</update>
where PushSettings is
public class PushSettings {
private List<PushSetting> settings;
private String userId;
}
it works fine

SQL - Update multiple records in one query

I have table - config.
Schema:
config_name | config_value
And I would like to update multiple records in one query. I try like that:
UPDATE config
SET t1.config_value = 'value'
, t2.config_value = 'value2'
WHERE t1.config_name = 'name1'
AND t2.config_name = 'name2';
but that query is wrong :(
Can you help me?
Try either multi-table update syntax
UPDATE config t1 JOIN config t2
ON t1.config_name = 'name1' AND t2.config_name = 'name2'
SET t1.config_value = 'value',
t2.config_value = 'value2';
Here is a SQLFiddle demo
or conditional update
UPDATE config
SET config_value = CASE config_name
WHEN 'name1' THEN 'value'
WHEN 'name2' THEN 'value2'
ELSE config_value
END
WHERE config_name IN('name1', 'name2');
Here is a SQLFiddle demo
You can accomplish it with INSERT as below:
INSERT INTO mytable (id, a, b, c)
VALUES (1, 'a1', 'b1', 'c1'),
(2, 'a2', 'b2', 'c2'),
(3, 'a3', 'b3', 'c3'),
(4, 'a4', 'b4', 'c4'),
(5, 'a5', 'b5', 'c5'),
(6, 'a6', 'b6', 'c6')
ON DUPLICATE KEY UPDATE id=VALUES(id),
a=VALUES(a),
b=VALUES(b),
c=VALUES(c);
This insert new values into table, but if primary key is duplicated (already inserted into table) that values you specify would be updated and same record would not be inserted second time.
in my case I have to update the records which are more than 1000, for this instead of hitting the update query each time I preferred this,
UPDATE mst_users
SET base_id = CASE user_id
WHEN 78 THEN 999
WHEN 77 THEN 88
ELSE base_id END WHERE user_id IN(78, 77)
78,77 are the user Ids and for those user id I need to update the base_id 999 and 88 respectively.This works for me.
instead of this
UPDATE staff SET salary = 1200 WHERE name = 'Bob';
UPDATE staff SET salary = 1200 WHERE name = 'Jane';
UPDATE staff SET salary = 1200 WHERE name = 'Frank';
UPDATE staff SET salary = 1200 WHERE name = 'Susan';
UPDATE staff SET salary = 1200 WHERE name = 'John';
you can use
UPDATE staff SET salary = 1200 WHERE name IN ('Bob', 'Frank', 'John');
maybe for someone it will be useful
for Postgresql 9.5 works as a charm
INSERT INTO tabelname(id, col2, col3, col4)
VALUES
(1, 1, 1, 'text for col4'),
(DEFAULT,1,4,'another text for col4')
ON CONFLICT (id) DO UPDATE SET
col2 = EXCLUDED.col2,
col3 = EXCLUDED.col3,
col4 = EXCLUDED.col4
this SQL updates existing record and inserts if new one (2 in 1)
Camille's solution worked. Turned it into a basic PHP function, which writes up the SQL statement. Hope this helps someone else.
function _bulk_sql_update_query($table, $array)
{
/*
* Example:
INSERT INTO mytable (id, a, b, c)
VALUES (1, 'a1', 'b1', 'c1'),
(2, 'a2', 'b2', 'c2'),
(3, 'a3', 'b3', 'c3'),
(4, 'a4', 'b4', 'c4'),
(5, 'a5', 'b5', 'c5'),
(6, 'a6', 'b6', 'c6')
ON DUPLICATE KEY UPDATE id=VALUES(id),
a=VALUES(a),
b=VALUES(b),
c=VALUES(c);
*/
$sql = "";
$columns = array_keys($array[0]);
$columns_as_string = implode(', ', $columns);
$sql .= "
INSERT INTO $table
(" . $columns_as_string . ")
VALUES ";
$len = count($array);
foreach ($array as $index => $values) {
$sql .= '("';
$sql .= implode('", "', $array[$index]) . "\"";
$sql .= ')';
$sql .= ($index == $len - 1) ? "" : ", \n";
}
$sql .= "\nON DUPLICATE KEY UPDATE \n";
$len = count($columns);
foreach ($columns as $index => $column) {
$sql .= "$column=VALUES($column)";
$sql .= ($index == $len - 1) ? "" : ", \n";
}
$sql .= ";";
return $sql;
}
Execute the code below to update n number of rows, where Parent ID is the id you want to get the data from and Child ids are the ids u need to be updated so it's just u need to add the parent id and child ids to update all the rows u need using a small script.
UPDATE [Table]
SET column1 = (SELECT column1 FROM Table WHERE IDColumn = [PArent ID]),
column2 = (SELECT column2 FROM Table WHERE IDColumn = [PArent ID]),
column3 = (SELECT column3 FROM Table WHERE IDColumn = [PArent ID]),
column4 = (SELECT column4 FROM Table WHERE IDColumn = [PArent ID]),
WHERE IDColumn IN ([List of child Ids])
Execute the below code if you want to update all record in all columns:
update config set column1='value',column2='value'...columnN='value';
and if you want to update all columns of a particular row then execute below code:
update config set column1='value',column2='value'...columnN='value' where column1='value'
Assuming you have the list of values to update in an Excel spreadsheet with config_value in column A1 and config_name in B1 you can easily write up the query there using an Excel formula like
=CONCAT("UPDATE config SET config_value = ","'",A1,"'", " WHERE config_name = ","'",B1,"'")
INSERT INTO tablename
(name, salary)
VALUES
('Bob', 1125),
('Jane', 1200),
('Frank', 1100),
('Susan', 1175),
('John', 1150)
ON DUPLICATE KEY UPDATE salary = VALUES(salary);
UPDATE 2021 / MySql v8.0.20 and later
The most upvoted answer advises to use the VALUES function which is now DEPRECATED for the ON DUPLICATE KEY UPDATE syntax. With v8.0.20 you get a deprecation warning with the VALUES function:
INSERT INTO chart (id, flag)
VALUES (1, 'FLAG_1'),(2, 'FLAG_2')
ON DUPLICATE KEY UPDATE id = VALUES(id), flag = VALUES(flag);
[HY000][1287] 'VALUES function' is deprecated and will be removed in a future release. Please use an alias (INSERT INTO ... VALUES (...) AS alias) and replace VALUES(col) in the ON DUPLICATE KEY UPDATE clause with alias.col instead
Use the new alias syntax instead:
official MySQL worklog
Docs
INSERT INTO chart (id, flag)
VALUES (1, 'FLAG_1'),(2, 'FLAG_2') AS aliased
ON DUPLICATE KEY UPDATE flag=aliased.flag;
just make a transaction statement, with multiple update statement and commit. In error case, you can just rollback modification handle by starting transaction.
START TRANSACTION;
/*Multiple update statement*/
COMMIT;
(This syntax is for MySQL, for PostgreSQL, replace 'START TRANSACTION' by 'BEGIN')
Try either multi-table update syntax
Try it copy and SQL query:
CREATE TABLE #temp (id int, name varchar(50))
CREATE TABLE #temp2 (id int, name varchar(50))
INSERT INTO #temp (id, name)
VALUES (1,'abc'), (2,'xyz'), (3,'mno'), (4,'abc')
INSERT INTO #temp2 (id, name)
VALUES (2,'def'), (1,'mno1')
SELECT * FROM #temp
SELECT * FROM #temp2
UPDATE t
SET name = CASE WHEN t.id = t1.id THEN t1.name ELSE t.name END
FROM #temp t
INNER JOIN #temp2 t1 on t.id = t1.id
select * from #temp
select * from #temp2
drop table #temp
drop table #temp2
UPDATE table name SET field name = 'value' WHERE table name.primary key
If you need to update several rows at a time, the alternative is prepared statement:
database complies a query pattern you provide the first time, keep the compiled result for current connection (depends on implementation).
then you updates all the rows, by sending shortened label of the prepared function with different parameters in SQL syntax, instead of sending entire UPDATE statement several times for several updates
the database parse the shortened label of the prepared function , which is linked to the pre-compiled result, then perform the updates.
next time when you perform row updates, the database may still use the pre-compiled result and quickly complete the operations (so the first step above can be omitted since it may take time to compile).
Here is PostgreSQL example of prepare statement, many of SQL databases (e.g. MariaDB,MySQL, Oracle) also support it.

Cancel Insert if inner query find nothing

I got the following query :
INSERT INTO contracts_settings (contract_id, setting_id, setting_value)
VALUES (:contract_id, (
SELECT setting_id
FROM settings
WHERE setting_type = :setting_type
AND setting_name = :setting_name
LIMIT 1
), :setting_value)
ON DUPLICATE KEY UPDATE setting_value = :setting_value
The value with the prefix : is replaced with data using PHP PDO::bindBalue.
If the inner query find nothing (it return NULL) but also INSERT a NULL statement. How to avoid that ?
Thanks.
Convert the INSERT ... VALUES syntax to INSERT ... SELECT:
INSERT INTO contracts_settings
(contract_id, setting_id, setting_value)
SELECT
:contract_id,
setting_id,
:setting_value
FROM settings
WHERE setting_type = :setting_type
AND setting_name = :setting_name
LIMIT 1
ON DUPLICATE KEY UPDATE
setting_value = :setting_value ;

How to Perform an UPSERT so that I can use both new and old values in update part

Stupid but simple example:
Assume I have a table 'Item' where I keeps totals of the items that receive.
Item_Name Items_In_Stock
Item name is primary key here. How to i achieve the following when ever I receive item A in quantity X.
If the item does not exist, I insert a new recored for Item A and set the items in stock to X and if there exists a record where items in stock was Y then the new value in items in stock is (X + Y)
INSERT INTO `item`
(`item_name`, items_in_stock)
VALUES( 'A', 27)
ON DUPLICATE KEY UPDATE
`new_items_count` = 27 + (SELECT items_in_stock where item_name = 'A' )
My problem is that i have multiple column in my actual table. Is it a good idea to write multiple select statements in the update part?
Of course I can do it in code but is there a better way?
As mentioned in my comment, you don't have to do the subselect to reference to the row that's causing ON DUPLICATE KEY to fire. So, in your example you can use the following:
INSERT INTO `item`
(`item_name`, items_in_stock)
VALUES( 'A', 27)
ON DUPLICATE KEY UPDATE
`new_items_count` = `new_items_count` + 27
Remember that most things are really simple, if you catch yourself overcomplicating something that should be simple then you are most likely doing it the wrong way :)
Although Michael's answer is the right one, you need to know a bit more to do the upsert programmatically:
First, create your table and specify which columns you want a unique index on:
CREATE TABLE IF NOT EXISTS Cell (
cellId BIGINT UNSIGNED,
attributeId BIGINT UNSIGNED,
entityRowId BIGINT UNSIGNED,
value DECIMAL(25,5),
UNIQUE KEY `id_ce` (`cellId`,`entityRowId`)
)
Then insert some values into it:
INSERT INTO Cell VALUES( 1, 6, 199, 1.0 );
Try doing the same thing again, and you'll get a duplicate key error, because cellId and entityRowId are same:
INSERT INTO Cell VALUES( 1, 6, 199, 1.0 );
Duplicate entry '1-199' for key 'id_ce'
That's why we use the upsert command:
INSERT INTO Cell ( cellId, attributeId, entityRowId, value)
VALUES( 1, 6, 199, 300.0 )
ON DUPLICATE KEY UPDATE `value` = `value` + VALUES(`value`)
This command takes the value 1.0 that's already there as value and does a value = value + 300.0.
So even after executing the above command, there will be only one row in the table, and the value will be 301.0.
You can get idea from this example:
Suppose you want to add user wise seven days data
It should have unique value for userid and day like
UNIQUE KEY `seven_day` (`userid`,`day`)
Here is the table
CREATE TABLE `table_name` (
`userid` char(4) NOT NULL,
`day` char(3) NOT NULL,
`open` char(5) NOT NULL,
`close` char(5) NOT NULL,
UNIQUE KEY `seven_day` (`userid`,`day`)
);
And your query will be
INSERT INTO table_name (userid,day,open,close)
VALUES ('val1', 'val2','val3','val4')
ON DUPLICATE KEY UPDATE open='val3', close='val4';
Example:
<?php
//If your data is
$data= array(
'sat'=>array("userid"=>"1001", "open"=>"01.01", "close"=>"11.01"),
'sun'=>array("userid"=>"1001", "open"=>"02.01", "close"=>"22.01"),
'sat'=>array("userid"=>"1001", "open"=>"03.01", "close"=>"33.01"),
'mon'=>array("userid"=>"1002", "open"=>"08.01", "close"=>"08.01"),
'mon'=>array("userid"=>"1002", "open"=>"07.01", "close"=>"07.01")
);
//If you query this in a loop
//$conn = mysql_connect("localhost","root","");
//mysql_select_db("test", $conn);
foreach($data as $day=>$info) {
$sql = "INSERT INTO table_name (userid,day,open,close)
VALUES ('$info[userid]', '$day','$info[open]','$info[close]')
ON DUPLICATE KEY UPDATE open='$info[open]', close='$info[close]'";
mysql_query($sql);
}
?>
Your data will be in table:
+--------+-----+-------+-------+
| userid | day | open | close |
+--------+-----+-------+-------+
| 1001 | sat | 03.01 | 33.01 |
| 1001 | sun | 02.01 | 22.01 |
| 1002 | mon | 07.01 | 07.01 |
+--------+-----+-------+-------+
This is the syntax for an upsert
INSERT INTO `{TABLE}` (`{PKCOLUMN}`, `{COLUMN}`) VALUES (:value)
ON DUPLICATE KEY UPDATE `{COLUMN}` = :value_dup';
If you have value for PK Column, or Unique Index on a column which satisfies unicity, You can use INSERT IGNORE, INSERT INTO ... ON DUPLICATE, or REPLACE
Example with INSERT IGNORE
INSERT IGNORE INTO Table1
(ID, serverID, channelID, channelROLE)
VALUES
(....);
Example with INSERT INTO .. ON DUPLICATE KEY UPDATE
SET #id = 1,
#serverId = 123545,
#channelId = 512580,
#channelRole = 'john';
INSERT INTO Table1
(ID, serverID, channelID, channelROLE)
VALUES
(#id, #serverId, #channelId, #channelRole)
ON DUPLICATE KEY UPDATE
serverId = #serverId,
channelId = #channelId,
channelRole = #channelRole;
Example with Replace
REPLACE INTO table1
(ID, serverID, channelID, channelROLE)
VALUES
(...);
Example for upsert
INSERT INTO table1 (col1, col2, col3)
VALUES ($1, $2, $3)
ON CONFLICT (col1)
DO
UPDATE
SET col2 = $2, col3 = $3
WHERE col1 = $1
RETURNING col1