I have searched for this information both on SO and on google, but have not found any authoritative answer.
When you have an update statement like:
UPDATE table SET rowA = rowB, rowB = NULL ...
It seems that:
ordering is not important (UPDATE table SET rowB = NULL, rowA = rowB)
nonetheless, the result is that rowA takes the prev value in rowB, because it seems that UPDATE first reads the previous values, then it updates them.
I would like to know if the two above points are true in general for SQL, i.e. if they are part of the SQL UPDATE semantics, if they are in the standard, or if it is an implementation details (and therefore subject to change).
Thanks!
EDIT: Let me stress that I would like an "authoritative" answer; I already tested on a number of SQL implementation that the behaviour is indeed the one depicted here. What I need is a "proof" that this is actually in the SQL standard/spec/semantics of UPDATE, with a link to the standard or, alternatively, to a surrogate reliable source (MSDN, dev.mysql.com, Oracle or PostgreSQL docs, ...)
James R. Groff, Paul N. Weinberg: SQL The complete reference (Osborne 1999), page 209 states
start quote
If an expression in the assignment list references one of the columns of the target table,
the value used to calculate the expression is the value of that column in the current row
before any updates are applied. The same is true of column references that occur in the
WHERE clause. For example, consider this (somewhat contrived) UPDATE statement:
UPDATE OFFICES
SET QUOTA = 400000.00, SALES = QUOTA
WHERE QUOTA < 400000.00
Before the update, Bill Adams had a QUOTA value of $350,000 and a SALES value of
$367,911. After the update, his row has a SALES value of $350,000, not $400,000. The
order of the assignments in the SET clause is thus immaterial; the assignments can be
specified in any order.
end quote
The same is supported by chapter 13.9 item 6, page 393, of a draft to the ANSI-92 SQL standard (X3H2-93-004), found here.
This is the most implementaion independent and the closest I could get so far.
Other sources of X3H2-93-004 can be found e.g. here (pg 590, item 15)
This is standard behaviour. When you reference a row, you refer to the pre-update version.
In SQL server the two row versions can be visualized with the output clause
update YourTable
set col1 = col1 + 1
output deleted.col1 -- Pre-update version of row
, inserted.col1 -- Post-update version of row
From the postgeSQL documentation for update (http://www.postgresql.org/docs/8.3/static/sql-update.html)
expression
An expression to assign to the column. The expression can use the old values of this and other columns in the table.
Related
I am new to BigQuery and was wondering if there was a way to search for a specific row, then individually update its columns using a Query. I am very new to database and SQL, and would love some of your help.
Yes you can. Typically this is achieved through data manipulation language (DML). For this specific example you would want use an UPDATE statement.
Documentation on this can be found here:
https://cloud.google.com/bigquery/docs/reference/standard-sql/dml-syntax#update_statement
As a word of caution verify your where clause before you execute to ensure you are targeting the correct rows.
For example:
UPDATE your_table
SET assigned_to_user = 'updated_value' -- the value you want to update to
WHERE -- this is where you define your criteria to narrow down to a subset of rows
criteria_column = 'target_values' -- this is your critera
-- and criteria_column_2 = 'other_value' -- if you need to expand more critiera just use logic operators like `and` or `or`
You can also test out what will be updated by issuing a select statement with the same criteria as your update and seeing which columns come back, for example:
select *
from your_table
WHERE
criteria_column = 'target_values'
When I am trying to update a column with character datatype using update statement. It says 0 rows update and does not throw any error. As the number of columns are much i tried using where clause using specific column out of it...where it updates the row.
Issue is when all the columns are used to alter the value, it gives back 0 rows updated. I have to automate it in vba code/tool so that it could update using all the rows. I identified the columns using which the value is not being updated but there is no error return.
It only says:
0 rows updated.
But what is wrong with that specific column(datatype...decimal).
Please help. I have searched whole internet but no results.
If you are trying to update a specific value in your database and only that one, you may have a rounding issue. This mean the value you see is not the exact value stored.
So you may try to update it with a specific range.
First select what you want to update:
select rowid from table_1
where val_x between <x>-<upsilon> and <x>+<upsilon>;
Update if you have only one value;
update table_1 set val_x = <new_val>
where val_x between <x>-0.001 and <x>+0.001
;
(otherwise, if more than 1 value, decrease <upsilon> to 0.0001, etc.)
Hope it helps
I need to create a query for updating a column in a table with values taken from another table and matching a field.
These are the 2 tables:
tblMain
ID Autonumbering
Key Text
Stat1 Integer
tblStat1
ID Autonumbering
Key Text
Freq Integer
I want to UPDATE the tblMain.Stat1 column with tblStat1.Freq value on each record in which tblMain.Key = tblStat1.Key.
I tried this syntax (found somewhere as an example)
UPDATE tblMain
SET tblMain.Stat1 = tblStat1.Freq
WHERE tblMain.Key = tblStat1.Key;
This doesn't work and returns an error on the 2nd row.
After some trials I found that the correct syntax (built with the Access query generator) is this:
UPDATE (tblMaibn INNER JOIN tblStat1 ON tblMain.Key = tblStat1.Key)
SET tblMain.Stat1 = tblStat1.Freq;
In this 2nd syntax, there is no trace of the WHERE condition.
Can someone help me to understand what's wrong with the 1st syntax.
Since I'm building a new table (the join), how can it work on tblMain?
As I said, I found the wrong syntax as an example of UPDATE statement.
Thank you in advance.
Bye,
Ivano
What is happening in your first query on the 2nd row, is that Access isn't aware of what tblStat1 represents in your query.
The reason your 2nd query is working is because it uses an inner join on the relevant key. In order for SQL to be aware of what record in tblMain relates to which record in tblStat1, you need to use a join.
You can see in the generated code that it is updating your desired table, but joining onto the second table. The where condition is redundant as you're updating every record.
In 1st syntax, you can change:
UPDATE tblMain
SET tblMain.Stat1 = (SELECT Freq
FROM tblStat1
WHERE tblMain.Key = tblStat1.Key)
Consider the following:
merge into T t1
using (select ID,Col1 from T where ID = 123) t2
on 1 = 0
when not matched then insert (Col1) values (t2.Col1);
Cominig from a programming background, to me this translates to:
"Evaluate false (i.e. 1 = 0), and when it is false (i.e. all the time), insert."
Is it not possible to just omit the match condition?
Is it because of my select's where condition that I'm confused here? Should this condition be moved to the on?
NOTE:
Due to restrictions with output, I cannot use insert. I need to output the results of this merge into a temporary table for reasons outside of the scope of what I'm asking.
In the answer you've linked to in the comments, as I've hopefully made clear, we are abusing the MERGE statement.
The query you've shown here could trivially be replaced by:
insert into T(Col1) select Col1 from T where ID = 123
However, if you want to be able to add an OUTPUT clause, and that OUTPUT clause needs to reference both the newly inserted data and data from the source table, you're not allowed to write such a clause on an INSERT statement.
So, we instead use a MERGE statement, but not for its intended purpose. The entire purpose is to force it to perform an INSERT and write our OUTPUT clause.
If we examine the documentation for MERGE, we see that the only clause in which we can specify to perform an INSERT is in the WHEN NOT MATCHED [BY TARGET] clause - in both the WHEN MATCHED and WHEN NOT MATCHED BY SOURCE clauses, our only options are to UPDATE or DELETE.
So, we have to write the MERGE such that matching always fails - and the simplest way to do that is to say that matching should occur when 1 = 01 - which, hopefully, is never.
1Since SQL Server doesn't support boolean literals
I have question regarding SQLite's changes() function, which, according to the documentation, "returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement" (also see the documentation of the underlying C/C++ function).
I was hoping to use this function to check whether the execution of an UPDATE statement pertaining to a single row has really caused that row to be changed or not.
By changed I do not just mean that the row matched the statement's WHERE clause. No, instead what I mean is that, for the row in question, the value of at least 1 column is actually different after the execution compared to before. If you ask me this is the only proper definition of a change in this context.
So I was hoping to detect such changes by checking whether changes() returns 1 (row changed) or 0 (row unchanged) when called right after the execution of the UPDATE statement.
But much to my despair this does not seem to work as expected.
Allow me to illustrate:
CREATE TABLE People (Id INTEGER PRIMARY KEY AUTOINCREMENT, Name TEXT NOT NULL);
INSERT INTO People (Name) VALUES ("Astrid");
SELECT changes();
Here changes() returns 1, as expected because we just INSERTed 1 row.
UPDATE People SET Name = "Emma" WHERE Id = 1;
SELECT changes();
Here changes() returns 1, as expected because 1 row was UPDATEd (i.e. actually changed: the Name of the Person with Id = 1 was "Astrid" but is now "Emma").
UPDATE People SET Name = "John" WHERE Id = 200;
SELECT changes();
Here changes() returns 0, as expected because there is no row with Id = 200.
So far so good. But now have a look at the following UPDATE statement, which does indeed match an existing row, but does not actually change it at all (Name remains set to "Emma")...
UPDATE People SET Name = "Emma" WHERE Id = 1;
SELECT changes();
Here changes() returns 1, while I was of course hoping for 0 :-(.
Perhaps this would have made sense if the function was called something like matched_rows() or affected_rows(). But for a function called changes(), and documented as it is, this behaviour strikes me as illogical, or confusing at best.
So anyway, can somebody explain why this happens, or, even better, suggest an alternative strategy to achieve my goal in a reliable (and efficient) way?
All I can think of is to actually do something like SELECT * FROM People WHERE Id = x, compare all returned column values with the values I'm about to set in the UPDATE statement and thereby decide whether I need to execute the UPDATE at all. But that can't be very efficient, right?
Of course in this toy example it might not matter much, but in my actual application I'm dealing with tables with many more columns, some of which are (potentially big) BLOBs.
The database does not compare old and new values; any UPDATEd row always counts as "changed" even if the values happen to be the same.
The documentation says that
the UPDATE affects … those rows for which the result of evaluating the WHERE clause expression as a boolean expression is true.
If you want to check the old value, you have to do it explicitly:
UPDATE People SET Name = 'Emma' WHERE Id = 1 AND Name IS NOT 'Emma';