SQL UPDATE: previous updated columns value in further columns - sql

Suppose I have this query:
UPDATE TEST SET
a = a + 23,
b = (b+5)/a,
c = c + a + b
WHERE
d = 6
OR
d = 10
and the original values of the columns is
a = 0
b = 5
c = 10
Will the query crash because of the 0 value of a (so (b+5)/a won't calculate) or will a already have value = 23.
The general question is: in an UPDATE statement, the values used to update the further columns are the original values of the already updated columns or the updated values?
Are there difference between the database used? MySQL, SQL Server, Oracle, DB2, ...?
EDIT
What would be the best practise to have the updated values on the "right side"?
Subqueries will work?
How to solve the problem of multiple values updated? Subqueries should return only 1 value
UPDATE TEST SET
a = a + 23,
b = (b+5)/(SELECT a FROM TEST WHERE d = 6),
c = c + a + b
WHERE
d = 6
OR
d = 10

In all SQL databases I know of except MySQL, all updates are done exactly simultaneously, which means a will be zero in the update of b.
In MySQL, the updates are done in order, which means a will be 23.
A very simple PostgreSQL example and a MySQL example with a different result.

In all ANSI compliant database systems, transactions are atomic and isolated, which means they happen all at once. Your query will crash for the given values.

Related

SQL tuple/lexicographic comparison with multiple directions

I need to return elements from a database query based on an inequality using the lexicographic ordering on multiple columns. As described in this question this is straightforward if I'm comparing all the columns in the same direction. Is there a straigtforward way to do this if I want to reverse the direction of the sort on some columns.
For instance, I might have columns A, B and C and values 5, 7, and 23 and I'd like to return something like:
WHERE A < 5 OR (A = 5 AND B > 7) OR (A = 5 AND B = 7 AND C < 23)
Is there any easier way to do this using tuples (I have to construct in a function without knowing the number of columns beforehand)? Note that, some columns are DateTime columns so I can't rely on tricks that apply only to integers (e.g. negating both sides). I'm happy to use postgresql specific tricks.
And, if not, is there a specific way/order I should build expressions like the above to best use multicolumn indexes?
Just thinking if going the CTE route and creating a column which stores 0 or 1 for whether the data passes the specific filter criteria or not.
WITH CTE AS
(
SELECT
..,
...,
CASE
WHEN A < 5 THEN 1
WHEN A = 5 AND B > 7 THEN 1
WHEN A = 5 AND B = 7 AND C < 23 THEN 1
ELSE 0
END AS filter_criteria
)
SELECT
..,
..
FROM
CTE
WHERE filter_criteria = 1
OR, directly applying the CASE statement in the WHERE clause. This reduces the extra step of CTE
WHERE 1 = CASE
WHEN A < 5 THEN 1
WHEN A = 5 AND B > 7 THEN 1
WHEN A = 5 AND B = 7 AND C < 23 THEN 1
ELSE 0
END
Referring to the thread you mentioned, can you try the idea WHERE (col_a, 'value_b') > ('value_a', col_b)

How can I update a dynamic amount of records in one SQL query?

An update query like:
UPDATE test
SET x = (case when id = 1 then 99
when id = 2 then 98
end),
y = (case when id = 1 then 42
when id = 2 then 41
end)
will update multiple records where the x and y attributes have different values for each record. But what if the number of records I need to update is dynamic? For simplicity, assume I have an array of id values. I want to update all the records that have an id in that array, and in one query. How could you do that?
It seems like you're already going about this the hard way. Your code is best accomplished with multiple queries:
UPDATE test
SET x = 99, y=42
WHERE id=1;
UPDATE test
SET x = 98, y=41
WHERE id=2;
As for updating "all the records" (as you say), that's a harder question to answer, as it's not clear where the data are coming from. That sort of thing might be best handled with a scripting language. You may have other options. depending on which database platform you're using, but you didn't specify that either.

Compare two unrelated tables sql

We're dealing with geographic data with our Oracle database.
There's a function called ST_Insertects(x,y) which returns true if record x intersects y.
What we're trying to do is, compare each record of table A with all records of table B, and check two conditions
condition 1 : A.TIMEZONE = 1 (Timezone field is not unique)
condition 2 : B.TIMEZONE = 1
condition 3 : ST_Intersects(A.SHAPE, B.SHAPE) (Shape field is where the geographical information is stored)
The result we're looking for is records ONLY from the table A that satisfy all 3 conditions above
We tried this in a single select statement but it doesn't seem to make much sense logically
pseudo-code that demonstrates a cross-join:
select A.*
from
tbl1 A, tbl2 B
where
A.TIMEZONE = 1 and
B.TIMEZONE = 1 and
ST_Intersects(A.SHAPE, B.SHAPE)
if you get multiples, you can put a distinct and only select A.XXX columns
With a cross-join rows are matched like this
a.row1 - b.row1
a.row1 - b.row2
a.row1 - b.row3
a.row2 - b.row1
a.row2 - b.row2
a.row2 - b.row3
So if row 1 evaluates to true on multiple rows, then just add a distinct on a.Column1, etc.
If you want to use the return value from your function in an Oracle SQL statement, you will need to change the function to return 0 or 1 (or 'T'/'F' - some data type supported by Oracle Database, which does NOT support the Boolean data type).
Then you probably want something like
select <columns from A>
from A
where A.timezone = 1
and exists ( select *
from B
where B.timezone = 1
and ST_intersects(A.shape, B.shape) = 1
)

Single SQL conditions in brackets

I am refactoring some old oracle sql statements containing plenty of conditions. Some are single conditions put into brackets. Now, does the brackets matter for single conditions? Is there a difference between the two examples below?
example 1
WHERE
(
A = B
AND B = C
)
AND ( A > 5 )
AND ( B <> 0 )
example 2
WHERE
(
A = B
AND B = C
)
AND A > 5
AND B <> 0
As far as I know there ain't any semantic differences.
In my experience usually this is either
a relic of some old condition (maybe an OR was in that bracket somewhere in the past) or
just the style of the dev working in this.
There is no difference between the two examples you have posted. Oracle query executes from the end i.e your where condition's last part is filtered first and runs back eg:- where first filter condition would be b<>0 then A>5 ,so on.
Its good practice to use brackets when using AND and OR operators together as without brackets soemtimes the logic is unclear ,otherwise with only AND operator bracket doesn't make any difference
What about logic: you do need brackets if you have some OR logic, but in this case (only AND) it has no meaning. You can remove all brackets in your query.
And if we'll go deep: look the explain query analyze, you can see that interpreter puts brackets automatically even you missed it.
All are same until you have only AND. But if you have any other operator then comes the question of precedence.
example 1
WHERE
(
A = B
AND B = C
)
AND ( A > 5 )
AND ( B <> 0 )
example 2
WHERE
(
A = B
AND B = C
)
AND A > 5
AND B <> 0
example 3
WHERE
A = B
AND B = C
AND A > 5
AND B <> 0

SQL UPDATE order of evaluation

What is the order of evaluation in the following query:
UPDATE tbl SET q = q + 1, p = q;
That is, will "tbl"."p" be set to q or q + 1? Is order of evaluation here governed by SQL standard?
Thanks.
UPDATE
After considering Migs' answer, I ran some tests on all DBs I could find. While I don't know what the standard says, implementations vary.
Given
CREATE TABLE tbl (p INT NOT NULL, q INT NOT NULL);
INSERT INTO tbl VALUES (1, 5); -- p := 1, q := 5
UPDATE tbl SET q = q + 1, p = q;
I found the values of "p" and "q" were:
database p q
-----------------+---+---
Firebird 2.1.3 | 6 | 6 -- But see "Update 2" below
InterBase 2009 | 5 | 6
MySQL 5.0.77 | 6 | 6 -- See "Update 3" below
Oracle XE (10g) | 5 | 6
PostgreSQL 8.4.2 | 5 | 6
SQLite 3.3.6 | 5 | 6
SQL Server 2016 | 5 | 6
UPDATE 2
Firebird 2.5 changes its behavior to match the majority of other SQL engines I tested, leaving MySQL alone. The relevant Release Notes entry, "Logic Change in SET Clause", strongly suggests that the majority behavior is correct per SQL specifications.
I've bugged MySQL to comment on this behavior (bug no. 52861), as they seem to be the outlier.
UPDATE 3
The aforementioned bug is today (2010-05-19) closed, and the documentation set to be updated to make this behavior explicit both in the UPDATE description and in the Differences from Standard SQL section.
Bravo, MySQL.
MySQL does "left to right" evaluation and does "see" the new values.
(Tested on 5.0.45-community-nt-log MySQL Community Edition)
Furthermore, from the MySQL manual: "Single-table UPDATE assignments are generally evaluated from left to right. For multiple-table updates, there is no guarantee that assignments are carried out in any particular order."
Now, "generally" is quite vague and "no guarantee" is very bad given that the order of evaluation is important.
So, in order to answer the question: IS the behaviour specified by "the SQL standard" or is it just a convention?
UPDATE: Got hold of the SQL92 specs which state at "13.10 update statement: searched" item "6) The (value expression)s are effectively evaluated for each row of T before updating any row of T."
IMHO not absolutely unambiguous, but enough to consider that the STANDARD is NOT to "see" the results of your own update.
Considering your example, the way Oracle, PostgreSQL and Interbase do it.
The UPDATE does not see the results of its work.
p will be set to q as of before update.
The following code will just swap the columns:
DECLARE #test TABLE (p INT, q INT)
INSERT
INTO #test
VALUES (2, 3)
SELECT *
FROM #test
p q
--- ---
2 3
UPDATE #test
SET p = q,
q = p
SELECT *
FROM #test
p q
--- ---
3 2
The write to the table has to occur after transaction that was well under way when the read was completed.