How to do 2 update statements at a time? - sql

update accounts set type=1 where id=2;
update accounts set type=3 where id=4;

At the same time? If you mean that you want to make sure no other queries affect the table before your queries are done, you're going to want to wrap them in a transaction.

exactly what you ask will be
update accounts set type = case id when 2 then 1 else 3 end where id in (2,4)
but in general this is of course impossibe.

This:
UPDATE ACCOUNTS t SET t.type = 1 WHERE t.id = 2; UPDATE ACCOUNTS t SET t.type = 3 WHERE t.id = 4;
...is acceptable SQL statement syntax - the ";" is a statement delimiter. The statements won't be executed simultaneously - nothing in a database is, everything is queued & processed in order of submission (though fiddling with isolation levels can work around that).
However, most APIs & IDEs prevent multiple statement execution like this in order to stop SQL injection attacks. What are you using that you find is stopping you from executing the statement?

If you want them to occur at once you could use a transaction:
SET autocommit=0;
START TRANSACTION;
update accounts set type=1 where id=2;
update accounts set type=3 where id=4;
COMMIT;
Note that you need to disable auto commit or the commit will occur when the first update occurs.

You may find this article interesting. I got more out of the comments than the article, but the article was interesting:
http://blog.bubble.ro/how-to-make-multiple-updates-using-a-single-query-in-mysql/
His technique probably won't work for you, but it is one approach.
The best bet would be to write a stored procedure and have it do the multiple updates, or, if there is some way for a program to determine the values for the second query, you could use a trigger, but I expect that won't help you.

It's not a generic solution but in this special case:
update accounts
set type = id - 1
where id = 2
or id = 4;
That's one statement...

Related

Update A Record if it exists, else do nothing, including short-cicruit

What I want to do is something that has the following logic:
IF EXISTS (SELECT * FROM people WHERE ID = 168)
THEN UPDATE people SET calculated_value = complex_queries_and_calculations
WHERE ID = 168
.., so to update a field of a given record if that record contains a given data, and else do nothing. To generate the data which would be used for the update, I need to query other tables for values and make some calculations. I want to avoid these queries + calculations, if there's actually nothing to update. And in this case, simply do nothing. Hence, I guess that putting for example an EXIST clause inside a WHERE clause of the UPDATE statement would end in many queries and calculations made in vain.
How can I only UPDATE conditionally and else do nothing, and make sure that all the queries + calculations needed to calculate the value used for the update are only made if the update is needed? And then, in the end, only do the update if complex_queries_and_calculations is not NULL?
My best solution so far uses a Common Table Expression (WITH clause), which makes it impossible to short-circuit. Anyway, such that you can understand the logic I'm trying to achieve, I'm showing what I've been trying so far (without success; code below is not working and I don't know why..):
-- complex queries and calculations; return result as t.result
WITH t AS(complex queries and calculations)
UPDATE target_table
SET
CASE
WHEN t.result IS NOT NULL
THEN target_table.target_column = t.result WHERE target_table.PK = 180
END;
UPDATES (Still saying syntax error, still not working)
WITH t AS(complex_queries_and_calculations AS stamp)
UPDATE target_table
SET target_column =
CASE
WHEN t.stamp IS NULL
THEN target_column
ELSE t.stamp
END
WHERE ID = 168;
Not even this is working (still reporting syntax error on UPDATE line):
WITH t AS(complex_queries_and_calculations AS stamp)
UPDATE target_table
SET target_column = target_column
WHERE ID = 168;
(eventual better approaches which avoid redundant target_column = target_column updates welcome)
With select it works, so I'm totally not understanding the syntax error #1064 it returns for my update query:
WITH t AS(complex_queries_and_calculations AS stamp)
SELECT
CASE
WHEN t.stamp IS NULL
THEN "Error!"
ELSE t.stamp
END
FROM t;
ADDITIONAL INFO
It seems like MariaDB actually does not support CTEs with UPDATE statements; correct me if I'm wrong... So I tried the following:
UPDATE people AS p
INNER JOIN (queries_and_calculations AS result) t
ON p.ID <> t.result -- just to join
SET p.target_column = t.result
WHERE p.ID = 168
AND t.result IS NOT NULL;
and now it's saying:
#4078 - Illegal parameter data types varchar and row for operation '='
Simply do the UPDATE. If there is no row with that ID, it will do nothing. This will probably be no slower than testing first.
Ditto for DELETE when the row might not exist.
"Upsert"/"IODKU" -- INSERT ... ON DUPLICATE KEY UPDATE ... is useful when you want to modify some columns when the row exists (according to some unique column), or add a new row (when it does not exist). This is better than doing a SELECT first.
Think of it this way... A big part of the UPDATE is
opening the table,
locating the block in the table that needs to be modified
loading that block into the cache ("buffer_pool")
All of that is needed for both your SELECT and UPDATE (yeah, redundantly). The UPDATE continues with:
If the row does not exist, exit.
Modify the row, and flag the block as "dirty".
In the background, the block will eventually be flushed to disk.
(I left out details about transactional integrity ("ACID"), etc.)
Even in the worst case, the whole task (for a single row) takes under 10 milliseconds. In the best case, it takes under 1ms and can be done somewhat in parallel with certain other activities.
There is no IF in SQL, since it is not needed:
UPDATE people p
SET calculated_value = c.val
FROM (
SELECT ID, val
FROM
... complex_queries_and_calculations
) c
WHERE c.ID = p.ID
AND ID = 168
AND v.val <> i.val -- maybe add this to avoid idempotent updates. Beware of NULLs, though!
;
~
GOT IT, The following query works to do exactly what I wanted in Mariadb :
UPDATE target_table
LEFT JOIN (complex_queries_and_calculations_to_get_update_value AS update_value) t
ON target_table.ID <> t.update_value -- serves just to have update value in memory,
-- because it needs to be accessed twice to create the updated column value
-- on update, sort of a workaround for CTE + UPDATE in MariaDB
SET target_column = JSON_ARRAY( FORMAT_UPDATE_VALUE(t.update_value),
FORMAT_2_UPDATE_VALUE(t.update_value) )
WHERE ID = 128 AND t.update_value IS NOT NULL;
If the record does not exist, the query takes about 0.0006 secs to execute, without doing anything to the table. If it does exits, it takes 0.0014 secs to execute, while updating the targeted record accordingly. So, it indeed seems to work and resources are saved if the targeted record is not found in target_table. Great thanks to all who helped!

SQL update multiple rows with different values where they match a value from a list

So perhaps the title is a little confusing. If you can suggest better wording for that please let me know and i'll update.
Here's the issue. I've got a table with many thousands of rows and i need to update a few thousand of those many to store latest email data.
For example:
OldEmail#1.com => NewEmail#1.com
OldEmail#2.com => NewEmail#2.com
I've got a list of old emails ('OldEmail#1.com','OldEmail#2.com') and a list of the new ('NewEmail#1.com','NewEmail#2.com'). The HOPE was was to sort of do it simply with something like
UPDATE Table
SET Email = ('NewEmail#1.com','NewEmail#2.com')
WHERE Email = ('OldEmail#1.com','OldEmail#2.com')
I hope that makes sense. Any questions just ask. Thanks!
You could use a case expression:
update mytable
set email = case email
when 'OldEmail#1.com' then 'NewEmail#1.com'
when 'OldEmail#2.com' then 'NewEmail#2.com'
end
where email in ('OldEmail#1.com','OldEmail#2.com')
Or better yet, if you have a large list of values, you might create a table to store them (like myref(old_email, new_email)) and join it in your update query, like so:
update t
set t.email = r.new_email
from mytable t
inner join myref r on r.old_email = t.email
The actual syntax for update/join does vary accross databases - the above SQL Server syntax.
With accuracy to the syntax in particular DBMS:
WITH cte AS (SELECT 'NewEmail#1.com' newvalue, 'OldEmail#1.com' oldvalue
UNION ALL
SELECT 'NewEmail#2.com', 'OldEmail#2.com')
UPDATE table
SET table.email = cte.newvalue
FROM cte
WHERE table.email = cte.oldvalue
or, if CTE is not available,
UPDATE table
SET table.email = cte.newvalue
FROM (SELECT 'NewEmail#1.com' newvalue, 'OldEmail#1.com' oldvalue
UNION ALL
SELECT 'NewEmail#2.com', 'OldEmail#2.com') cte
WHERE table.email = cte.oldvalue
Consider prepared statement for rows update in large batches.
Basically it works as following :
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 skipped).
Here is PostgreSQL example of prepare statement, many of SQL databases (e.g. MariaDB,MySQL, Oracle) also support it.

Limit a value in SQL

Not that familiar with SQL.
I have the follow SQL :
UPDATE my_Table
SET num = num + 1
WHERE id = 1
I would like limit that num column that it won't exceed a threshold, assuming 100. If num will reach 100, I would like it to stay 100 and will not increase.
I assume if statement should be included here somehow. but cant figure out how.
I'm seeing answers that would solve your problem from an update statement, all fine whatever way it is done.
Until someone creates a statement that doesn't adhere to your constraint, like a new co-worker, someone sleepy that forgets it or whatever reason. You should probably know about other options to force this rule.
You could create an SQL constraint that checks that num is never set to more than 100. That way any update or insert statement that makes this value more than 100 would result in an error rather than doing the insert or update.
Another way to force this rule "under the hood", not really beginner level, would be to create an update and insert trigger that would check for num being more than 100 and reset it to 100 in that case. That wouldn't result in an error when you run the insert or update statement. I don't have a good link for ANSI-SQL triggers, but each RDBMS has good documentation.
You can use a CASE expression:
UPDATE my_Table
SET num = CASE WHEN num+1 >= 100 THEN 100 ELSE num+1 END
WHERE id=1
try:
UPDATE my_Table SET num=num+1 WHERE id=1 AND num<=99
in that case you can use IIF for shorter version
UPDATE my_Table SET num=(IIF((num+1)>100,num,num+1)) WHERE id=1

Enhance SQL script to better handle more than one result from subquery

I wrote a set of queries for work awhile back that identify records on a large number of tables that our Windows application has locked. I recently attempted to enhance them so that they also unlock the records identified.
My current implementation requires you to run the script repeatedly if there is more than one locked entry on any of the tables. It feels like there is a better way to do this, but my SQL skills are "advanced beginner." What would be a better implementation? (MS SQL Server 2005, 2008)
/* Unlock Remark table */
DECLARE #LockedRemarkID NCHAR(36)
SET #LockedRemarkID = (SELECT TOP 1 RemarkId -- Top 1 prevents failure if result set >1
FROM Remark
WHERE RemarkConsumerId = #ConsumerVar
AND CurrentTransactionId IS NOT NULL)
UPDATE Remark
SET CurrentTransactionId = NULL
WHERE RemarkId = #LockedRemarkID
Why not do all the updates in the same update script:
UPDATE
Remark
SET
CurrentTransactionId = NULL
WHERE
RemarkConsumerId = #ConsumerVar
AND
CurrentTransactionId IS NOT NULL

Update statement clarification

I'm extremely new to "updating" databases as I've only ever wrote queries as select statements.
I have a record i need to delete or change from the database. How would I go about doing that? Lets take updating a column first.
I want to update the "Customer" table and the "SNumber" column where the "TicketNum" Column is "123" Right now "SNumber" for that record is blank, and i'd like it to be "115"
I was thinking:
update Customer
set snumber = '115'
where ticketnum = '123'
Obviously I do not want to run this query with fear of messing up the database.
The second part of this is how would I delete the record all together?
Thanks
that is correct.
remember you can update and then issue a ROLLBACk if you need to undo it.
delete is similar:
delete customer where ticketnum = 123;
If you are new I recommend searching about CRUD operations using tSQL. For example:
Update on MSDN
Delete on MSDN
As for your question. You will not mess up the database with that UPDATE clause, it is correct.
To delete the row just use:
DELETE FROM Customer
WHERE ticketnum = '123'
ROLLBACK, as recommended on other answer, helps to roll back an action (transaction) that was incorrect or erroneus or just because some data is not correct. See MSDN for ROLLBACK sintax
This is closely related to TRANSACTIONS concept.
The general form of update in SQL is
UPDATE table
SET column = expression
WHERE predicates;
and an example would be
UPDATE suppliers
SET description = 'gorilla glass', product = 'screens'
WHERE name = 'corning';
As other posters have noted, your SQL update is correct.