Are updated fields processed sequentially in an SQL Statement - sql

If I wanted to move data from one field into another field within the same record and then remove the data from the existing field can this reliably be done in one SQL statement, and is this dependent on the Database Provider?
An example of the SQL I am thinking about is below
UPDATE table SET field2 = field1, field1 = '' WHERE keyField = 1
Thanks for any help

Yes, it is reliable because major DB's like Oracle, SQL Server, MySQL, etc. are transactional, which ensure ACID. In other words, it's an all-or-nothing scenario, all changes happen or non happen (if a transaction is rolled-back for example).
However it is not sequential; i.e. doing this would yield the same result:
UPDATE table SET field1 = '', field2 = field1 WHERE keyField = 1
Rather, your SQL is doing something like this:
UPDATE table
SET field2_NewValue = field1_OriginalValue
, field1_NewValue = ''
WHERE keyField = 1

Related

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.

Dealing with multiple output results in UPSERT query [SQL]

I'm trying to do an update query in which a single row the table is updated and, if nothing has matched and updated, a new row is inserted. In each case, I need the query to return the ID of the inserted row.
The issue I'm having is this query is returning 2 separate results when the insert case is reached, one for each output (the first empty, the second containing the ID). I'm running this query using SQL Alchemy on python and I'm only able to see the first result, which is empty.
UPDATE [Rights]
SET accessLevel = :access_level
OUTPUT inserted.rightsID
WHERE principal = :principal and [function] = :function
IF ##ROWCOUNT = 0
INSERT INTO Rights(principal, [function], accessLevel)
OUTPUT inserted.rightsID
VALUES(:principal, :function, :access_level)
And I'm calling it like so:
inserted_right_id = session.execute(sql_rights_update, right).fetchall()
Can anyone recommend a way of changing the query so that I can still use the UPSERT method, but only receive one of the IDs? I was considering storing the OUTPUT values into a table and returning that, or wrapping the whole thing in a select but hopefully there's something more elegant out there.
Thanks a million.
Feeling quite dumb. I simply added a
IF EXISTS(SELECT * FROM Rights WHERE principal = :principal and [function] = :function)
UPDATE ...
ELSE
INSERT ...

SQL SERVER - delimited identifiers [] don't work when running an Update Query on a Linked Server table

So I have a linked server (access mdb database) in SQL SERVER. I have a table in there called XX2 Sectors (yes i know that white spaces in table names/columns are a bad practice but I don't have any control over it in this case).
When I run a SELECT query in a form
SELECT * FROM [Server_Name]...[XX2 Sectors]
it works completely fine, BUT when I am running and UPDATE query on this table e.g.
UPDATE [Server_Name]...[XX2 Sectors] SET Column_Name = 'Variable' WHERE
Column_Name = 'whatever'`
I get an error: OLE DB provider "Microsoft.ACE.OLEDB.12.0" for linked server "Server_Name" returned message "The Microsoft Access database engine cannot find the input table or query 'XX2'. Make sure it exists and that its name is spelled correctly."
-> So basicaly it cuts off the table name at the white space point which [] should prevent... But if I rename the table from XX2 Sectors to XX2_Sectors -> effectively removing the white space then the UPDATE query works fine.
Any thoughts? I think i tried everything and I am now at a loss...
Thank you.
Try to use QUOTENAME.
Returns a Unicode string with the delimiters added to make the input
string a valid SQL Server delimited identifier.
QOUTENAME(XX2 Sectors) instead of [XX2 Sectors]
UPDATED: So the answer was that for some reason when you use linked server is SQL Sever (bug or not I don't know) but if you try to update a filed table in the Linked Datasheet (and it is Access) based on the value of the field it won't work unless you update something else as well or choose another criteria. For Example:
UPDATE TABLE SET FIELD1 = Z WHERE FIELD1 = X
will not work, BUT
UPDATE TABLE SET FIELD1 = Z WHERE FIELD2 = X
OR
UPDATE TABLE SET FIELD1 = Z, FILED2 = F WHERE FIELD1 = Y
OR
UPDATE TABLE SET FIELD1 = Z, FIELD2 = FIELD2 WHERE FIELD1 = X
Will work fine.
-------- OLD ANSWER BELOW ------
After 3 hours I found the solution for this problem which unfortunately means there is no solution as the problem resolved itself after I had launch...

Firebird query giving weird results

I have a table with two fields defined as varchar(15). I want to know which records have the same value in both fields:
select * from table where field1 = field2
this returns a null result though I know there are records that match. What am I doing wrong?
Without further information (see my comments), the problem might be a corrupted index. What happens when you try:
select * from table where field1 || '' = field2 || ''
Using this query will make Firebird ignore the index (if any) and do a full table scan.
If this does return a result, you will want to validate and maybe repair the database (using gfix) and either backup and restore the database or drop and recreate the index.

Skip updating SQL row with empty values?

I have a table with several columns that allow NULLs. How would I go about writing a SQL Query that will allow me to skip that column in an update if the value is "empty". Should I use a boolean flag letting the query know to update that value? I do something similar in a SELECT like this
SELECT * FROM table WHERE (#boolFlag = 1 OR col1 = #col1Val)
But trying to do that for an update has proven to be an exercise in futility. Ideally I'd be able to say skip this value if true, otherwise update over my 20ish columns. Right now I can't pass in DBNull.Value, so instead I'm being forced to insert "" which is converted into whitespace (for instance, my nvarchar(50) has 50 spaces).
I'm using a SQL Server DB/Table and a DataSet in VB.NET, constructing my queries in VS2k8 if that matters.
You could do:
update MyTable
set MyColumn = case when #MyColumnValue = '' then null else #MyColumnValue end
A short form of the above would be:
update MyTable
set MyColumn = case when #MyColumnValue <> '' then #MyColumnValue end