简体   繁体   中英

SQL update execution order matters?

I was always of the understanding that during a SQL UPDATE the existing values would remain until the entire update statement was complete, but I am seeing different behaviour in practice.

Inventory
-----------------------------
date        base  flexible
2014-05-01  5     10
2014-05-02  5     10

UPDATE Inventory SET base = GREATEST(0, base - 7), flexible = flexible - GREATEST(0, (7 - base)) WHERE date = '2014-05-01'

UPDATE Inventory SET flexible = flexible - GREATEST(0, (7 - base)), base = GREATEST(0, base - 7) WHERE date = '2014-05-02'

Inventory
-----------------------------
date        base  flexible
2014-05-01  0     3
2014-05-02  0     8

In the first example it seems that base is updated to zero with the first expression, causing the second expression to evaluate incorrectly (7 - 0) instead of (7 - 5) .

Can anyone explain what is going on here?

MySQL breaks the standard a bit;

It updates columns using the current field value considering the field order in the update instead of following the SQL standard which uses the field value from before the update statement.

From the docs ;

If you access a column from the table to be updated in an expression, UPDATE uses the current value of the column. The second assignment in the following statement sets col2 to the current (updated) col1 value, not the original col1 value. The result is that col1 and col2 have the same value. This behavior differs from standard SQL.

UPDATE t1 SET col1 = col1 + 1, col2 = col1;

您将在提交之前看到自己的更改,而其他人则不会。

Take a look on this . I think it is because of GREATEST function...

How about storing base value in user variables, like this:

UPDATE Inventory
SET base = (@base := base), flexible = (@flexible := flexible),
    base = GREATEST(0, @base - 7),
    flexible = @flexible - GREATEST(0, (7 - @base));

Here are tests:

mysql> insert into Inventory values('2014-05-01', 5, 10);
Query OK, 1 row affected (0.00 sec)

mysql> insert into Inventory values('2014-05-02', 5, 10);
Query OK, 1 row affected (0.00 sec)

mysql>
mysql>     UPDATE Inventory
    ->     SET base = (@base := base), flexible = (@flexible := flexible),
    ->         base = GREATEST(0, @base - 7),
    ->         flexible = @flexible - GREATEST(0, (7 - @base));
Query OK, 2 rows affected (0.00 sec)
Rows matched: 2  Changed: 2  Warnings: 0

mysql> SELECT * FROM Inventory;
+------------+------+----------+
| date       | base | flexible |
+------------+------+----------+
| 2014-05-01 |    0 |        8 |
| 2014-05-02 |    0 |        8 |
+------------+------+----------+
2 rows in set (0.00 sec)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM