UPDATE multiple rows with different values in one query in MySQL - 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

Related

Update with switch and inner join

I am given a table for a range of option codes, models and availability from someone else. Currently these are updated by hand in the back-end (I know...) and take a whopping 3 months. I want to automate the process, I tried using CASE WHEN but it seems Access cannot handle it. I ran a query that updated based on one clause and it worked fine, see below. Table 1 is in my db, Table 2 is the data I am given translated in to a usable format. It is just a table with 2 columns; option codes and availability (relevant to a specific model)
UPDATE Table1
SET Table1.Availability = 'Y'
WHERE
(
SELECT Table1.Availability
FROM Table1
INNER JOIN Table2
ON Table1.Code = Table2.Code
WHERE Table2.Availability='OPT'
)
This works but would require a new query for every availability type. Below is my attempt at updating for each availability type. It says there is a syntax error # Switch(...
UPDATE Table1
SET Table1.Availability =
Switch(
Table2.Availability = 'OPT', 'Y',
Table2.Availability = 'STD', 'S',
Table2.Availability = 'DEL', 'N'
)
FROM Table1
INNER JOIN Table2
ON Table1.Code = Table2.Code
WHERE ModelCode = '1234'
;
I'm not sure if I am using switch correctly here, help appreciated. If it isn't clear pretty much what I want is If Table2.Availability = OPT, UPDATE Table1.Availability to 'Y' where Code is the same and Model = specific model
I have to specify a model code as the availability for a given option code (Code) is unique. The data I am given is a mess and it is easiest to sort it in to model specific data.
Thanks in advance :)
Consider the following tested and working syntax:
UPDATE Table1
INNER JOIN Table2
ON Table1.Code = Table2.Code
SET Table1.Availability =
Switch(
Table2.Availability = 'OPT', 'Y',
Table2.Availability = 'STD', 'S',
Table2.Availability = 'DEL', 'N'
)
WHERE ModelCode = '1234'
;

Update SQL records with values from another record

I'm spinning in circles trying to figure out what is likely a very simple SQL structure. My task seems simple - within the same table I need to update 3 related records with data from one master record. The master coordinates are in the record with a class of 'T', and I want to insert that record's coordinates into the rx_latitude/longitude columns of the related records with class code 'R'
The table structure is: callsign, class, tx_latitude, tx_longitude, rx_latitude, rx_longitude. Sample data looks like this:
J877, T, 40.01, -75.01, 0, 0
J877, R, 39.51, -75.21, 0, 0
J877, R, 40.25, -75.41, 0, 0
J877, R, 39.77, -75.61, 0, 0
Within that same table, I want to populate all of the rx_latitude and rx_longitude fields where the class is 'R' with the tx_latitude and tx_longitude coordinates where the class is 'T' and the callsign matches.
I've tried several insert and update statements, but I can only seem to operate on the master record, not the related records. I would appreciate any guidance that you might offer.
You can use UPDATE...FROM statement:
UPDATE theTable
SET
tx_latitude = masterRecord.tx_latitude,
tx_longitude = masterRecord.tx_longitude
FROM
(SELECT tx_latitude,tx_longitude,callsign FROM theTable WHERE class='T') masterRecord
WHERE
class='R' AND callsign = masterRecord.callsign
Updated
Try :
update yourTable t1, yourTable t2 set
t1.tx_latitude = t2.tx_latitude,
t1.tx_longitude = t2.tx_longitude
where t1.class = 'R' and t2.class = 'T' and t1.callsign = t2.callsign
Example
You can use MySQL's update ... join syntax.
It would go something like this:
update yourtable toUpdate
left join yourtable masterRecordTable
on toUpdate.callsign = masterRecordTable.callsign and masterRecordTable.class = 'T'
set toUpdate.rx_latitude = masterRecordTable.tx_latitude,
toUpdate.rx_longitude = masterRecordTable.tx_longitude
where toUpdate.callsign = 'J877' and toUpdate.class = 'R'
See this fiddle for a working example

MySQL query Find and Replace in Specific Columns in a Table?

I need to set all values in certain columns...to 1 (where they are now NULL)
Can anyone help out with a little assist on this SQL query/command syntax?
I need to replace several columns where the SchoolID is 184 with a 1, something like this?
SELECT * FROM tblMembers WHERE SchoolID SET column = '1';
You need to use an UPDATE statement:
UPDATE tblMembers
SET column = '1'
WHERE SchoolID = '184'
You can set multiple columns at the same time:
UPDATE tblMembers
SET column = '1', column2 = 'somethingelse', column3 = 'somethingelse'
WHERE SchoolID = '184'

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 ;

Merge not inserting. No error

Can someone tell me why this insert is failing but not giving me an error either? How do I fix this?
merge table1 as T1
using(select p.1,p.2,p.3,p.4,p.5 from #parameters p
inner join table1 t2
on p.1 = t2.1
and p.2 = t2.2
and p.3 = t2.3
and p.4 = t2.4) as SRC on SRC.2 = T1.2
when not matched then insert (p.1,p.2,p.3,p.4,p.5)
values (SRC.1,SRC.2,SRC.3,SRC.4,SRC.5)
when matched then update set t1.5 = SRC.5;
The T1 table is currently empty so nothing can match. The parameters table does have data in it. I simply need to modify this merge so that it checks all 4 fields before deciding what to do.
You can't select from a variable: from #parameters
See the following post: Using a variable for table name in 'From' clause in SQL Server 2008
Actually, you can use a variable table. Check it out:
MERGE Target_table AS [Target]
USING #parameters AS [Source]
ON (
[Target].col1 = [Source].col1
AND [Target].col2 = [Source].col2
AND [Target].col3 = [Source].col3
AND [Target].col4 = [Source].col4
)
WHEN NOT MATCHED BY TARGET
THEN INSERT (col1,col2,col3,col4,col5)
VALUES (
[Source].col1
,[Source].col2
,[Source].col3
,[Source].col4
,[Source].col5
)
WHEN MATCHED
THEN UPDATE SET [Target].col5 = [Source].col5;