Update multiple rows with multiple values and multiple conditions mysql - mysql

I am facing a complex situation of SQL queries. The task is to update multiple rows, with multiple values and multiple conditions. Following is the data which I want to update;
Field to update: 'sales', condition fields: 'campid' and 'date':
if campid = 259 and date = 22/6/2011 then set sales = $200
else if campid = 259 and date = 21/6/2011 then set sales = $210
else if campid = 260 and date = 22/6/2011 then set sales = $140
else if campid = 260 and date = 21/6/2011 then set sales = $150
I want to update all these in one query.

Try this:
UPDATE your_table SET sales =
CASE
WHEN campid = 259 AND date = 22/6/2011 THEN 200
WHEN campid = 259 AND date = 21/6/2011 THEN 210
WHEN campid = 259 AND date = 22/6/2011 THEN 140
WHEN campid = 259 AND date = 21/6/2011 THEN 150
ELSE sales
END
Naturally I don't know if date field is really DATE or DATETIME, so I left query showing what you can do, but maybe you have to fix dates comparison according to data type.
If date field is DATE (as it should) you can write AND date = '2011-06-22' and so on.
Note ELSE condition: it's necessary to avoid records not falling inside other cases will be set to NULL.

Rather than write a sql query that is far too complicated and time involved, I believe you would be better off spending your time writing a data access object to handle these rather simple manipulations on a per record basis. This makes later maintenance of the code, along with development of new code using your data access objects far easier than a one time use, intricate sql query.

You certainly should not do these in a single query. Instead, if what you aim for is to update them atomically, all at the same time, you should issue several UPDATE statements in a single transaction.
You do not say which MySQL version you use, and not which storage engine. Assuming InnoDB - which is the standard in recent versions of MySQL and should generally be used for transactional systems - and also assuming you are doing this from the command line client, you would
mysql> set autocommit=0;
mysql> UPDATE ....;
mysql> UPDATE ....;
mysql> ...
mysql> commit;
You can then reenable autocommit if you like by repeating the first line, but with a value of 1:
mysql> set autocommit=1;

Related

Update multiple table with different WHERE clause in one query

I want to combine three different UPDATE queries, in different table, with different WHERE conditions, into a single mySql query. Is it possible?
Reason: send 1 request to mySql server is faster than sending 3
requests separately :)
UPDATE client SET clientCount = clientCount + 1 WHERE clientType = 2
UPDATE storage SET soldItem = soldItem + 1 WHERE itemType = 5
UPDATE employee SET doWork = 1, totalSale = totalSale + 1 WHERE employeeId = 12
The UPDATE statements are independent, and are not related to each other. I tried to find some solution, however, the
UPDATE client, storage, employee SET client.clientCount = ... , storage.soldItem = ... WHERE ... ? ? ? ...
does not fit to my case as my three UPDATE statements are independent...
Is it possible to combine 3 independents queries into a 1 query?
Create a stored procedure with all these update statements and call the stored procedure from your code.

MySQL- Select and Update at the same time

I have this query
SELECT * FROM outbox where Status=0 ;
then I need to update the selected records so Status should be equal 1
i.e (UPDATE outbox(selected records from SELECT query) SET Status =1 )
any help ?
This is a much harder problem than it sounds. Yes, in the simplistic case where you are only thinking of one user and a few records, it seems easy. But, databases are designed to be ACID-compliant, with multiple users and multiple concurrent transactions that can all be affecting the data at the same time. And there is no single statement in MySQL that does what you want (other databases support an OUTPUT clause, RETURNING or something similar).
One structure that will work in MySQL is to place the items in a temporary table, then do the update, then return them. The following shows the semantics using transactions:
start transaction;
create temporary table TempOutboxStatus0 as
select *
from outbox
where status = 0;
update outbox o
set status = 1
where status = 0;
select *
from TempOutboxStatus0;
commit;
For the update, I actually prefer:
where exists (select 1 from TempOutboxStatus0 t where t.outboxid = o.outboxid);
because its intention is clearer -- and the code is safer in case the conditions subtly change.
Note: you may want to use explicit table locks. Such considerations depend on the storage engine you are using.
BEGIN
Start transaction;
SELECT *
FROM
outbox
where
Status = 0 and
Is_Expired = 0 and
Service_ID=p_service_id
order by
Next_Try_Date asc FOR Update;
update outbox
set
Status=1
where
Status = 0 and
Is_Expired = 0 and
Service_ID=p_service_id;
commit;
END
is this possible .. it seems it works with me
You can do something like that, the outbox is your table:
update outbox set Status = 1 where Status = 0
you can do it like below
$sql=mysql_query("SELECT * FROM outbox where `Status`=0");
while($result=mysql_fetch_array($sql))
{
$update="UPDATE `outbox` SET `Status` =1 where
'your column name'='your previous fetched value');
}

Conditional UPDATE if new_value <= value_from_different_row

Is there an elegant solution to perform an UPDATE in MySQL if and only if the value to be assigned to column X in my row is greater or equal to the same column X's value in another (specific) row?
I'm using a table with 2 columns as a key => value store, and I have something like this:
key | value
---------------------------
period_a_begin | 2014-01-01
period_a_end | 2014-01-15
period_b_begin | 2014-01-20
period_b_end | 2014-02-15
How can I make sure that the new value for period_a_end is greater or equal to the value of period_a_begin value and less or equal to the value of period_b_begin in the same SQL query that I use to update period_a_end?
I've tried using subqueries, but without success:
UPDATE configtable
SET configtable.value=:myvalue
WHERE configtable.key="period_a_end"
AND :myvalue >= (SELECT configtable.value FROM configtable WHERE configtable.key = "period_a_begin")
AND :myvalue <= (SELECT configtable.value FROM configtable WHERE configtable.key = "period_b_begin");
I keep getting the following error:
You can't specify target table configtable for update in FROM clause
While I understand why that error pops up, I fail to find a way to find a way to make this work without removing the whole check from my prepared statement. :/
Any ideas?
This isn't so elegant, but it should work. You can use an additional level of nested queries:
UPDATE configtable
SET configtable.value = :myvalue
WHERE configtable.key="period_a_end" AND
:myvalue >= (select value from (SELECT ct.value FROM configtable ct WHERE ct.key = "period_a_begin") ct) AND
:myvalue <= (select value from (SELECT ct.value FROM configtable ct WHERE ct.key = "period_b_begin") ct);
In the end, I've chosen to implement my check in PHP using multiple queries, packing the whole check into a single SQL transaction. But beware that transaction to not work with the MyISAM storage engine, so you'll have to use InnoDB or some other engine that supports transactions.
Besides being faster then stored procedures, this solution also seems more portable (at least on the database side) to me.

How to select rows from a growing MySQL table incrementally

I have a MySQL table that grows very rapidly. I would like to have an ongoing process (e.g. running every 30 minutes) that selects all the rows that are "new" since the last time the process was run. The table has an AUTO_INCREMENT column called id, and I thought I could use it to make sure I'm getting all the records. Here was the approach:
Initialize
LAST_ID_SELECTED = 0
Run repeatedly, forever:
startID = 1 + LAST_ID_SELECTED
nextAutoIncrementID = getQuery("SELECT AUTO_INCREMENT FROM information_schema.tables WHERE TABLE_NAME = 'myTable'")
lastID = nextAutoIncrementID - 1
data = SELECT * FROM myTable WHERE id BETWEEN startID AND lastID
LAST_ID_SELECTED = lastID
However, I don't think this will actually work: I'm worried that I can get my (startID, lastID) range and make my select query before all the inserts for the ids <= lastID have been completed. So I won't actually get all the rows in the range (startID,lastID).
What's the right way to do this?

More efficient way to write multiple UPDATE queries

Is there a better / more efficient / shorter way to write this SQL Query:
UPDATE mTable SET score = 0.2537 WHERE user = 'Xthane' AND groupId = 37;
UPDATE mTable SET score = 0.2349 WHERE user = 'Mike' AND groupId = 37;
UPDATE mTable SET score = 0.2761 WHERE user = 'Jack' AND groupId = 37;
UPDATE mTable SET score = 0.2655 WHERE user = 'Isotope' AND groupId = 37;
UPDATE mTable SET score = 0.3235 WHERE user = 'Caesar' AND groupId = 37;
UPDATE mTable
SET score =
case user
when 'Xthane' then 0.2537
when 'Mike' then 0.2349
when 'Jack' then 0.2761
when 'Isotope' then 0.2655
when 'Caesar' then 0.3235
else score
end
where groupId = 37
You can use a CASE statement to perform this type of UPDATE.
UPDATE mTable
SET score
= CASE user
WHEN 'Xthane' THEN 0.2537
WHEN 'Mike' THEN 0.2349
WHEN 'Jack' THEN 0.2761
WHEN 'Isotope' THEN 0.2655
WHEN 'Caesar' THEN 0.3235
ELSE score
END
WHERE groupId = 37
You could create a temporary table, insert score, user and groupid for all the records you want to update then do something like this:
UPDATE
FROM mTable m
INNER JOIN tmpTable t
ON m.groupId = t.groupId
AND m.user = t.user
SET m.score = t.score;
Your original statements look short enough, and are easy enough to understand, and you can determine whether there were any rows affected on each of those separate UPDATE statements.
For a large number of statements, however, there's a considerable amount of overhead making "roundtrips" to the database to execute each individual statement. You can get much faster execution (shorter elapsed time) for a large set of updates by "batching" the updates together in a single statement execution.
So, it depends on what you are trying to achieve.
Better? Depends on how you define that. (Should the statements be more understandable, easier to debug, less resource intensive?
More efficient? In terms of reduced elapsed time, yes, there are other ways to accomplish these same updates, but the statements are not as easy to understand as yours.
Shorter? In terms of SQL statements with fewer characters, yes, there are ways to achieve that. (Some examples are shown in other answers, but note that the effects of the statements in some of those answers is significantly DIFFERENT than your statements.)
The actual performance of those alternatives is really going to depend on the number of rows, and available indexes. (e.g. if you have hundreds of thousands of rows with groupId = 37, but are only updating 5 of those rows).