我正在尝试在MySQL事务中运行多个更新语句,但我需要在每个语句中使用WHERE子句来引用事务开始之前存在的值。 (使用innoDB表。)
例如,我有以下航班表(简化,显然):
flight aircraft dep_time
1 1 05:00
2 1 06:00
3 1 07:00
4 2 05:00
5 2 06:00
6 2 07:00
我需要做的是在06:00或更晚的飞机1上交换航班,飞机2的航班在06:00或更晚离开。我目前这样做是通过为每个航班分配一架中间飞机,然后用这架中间飞机更新飞机到所需的飞机。例如:
UPDATE flights SET aircraft = 1001 WHERE aircraft = 1 AND dep_time >= 06:00
UPDATE flights SET aircraft = 1002 WHERE aircraft = 2 AND dep_time >= 06:00
UPDATE flights SET aircraft = 2 WHERE aircraft = 1001
UPDATE flights SET aircraft = 1 WHERE aircraft = 1002
似乎我可以通过使用事务来避免两个额外的更新语句。另外,如果数据库中实际存在飞机1001,我现在使用的方法会引起严重问题(此时我只是使用非常大的数字来确保不会发生这种情况)......我想避免。我的意图是做这样的事情:
START TRANSACTION();
UPDATE flights SET aircraft = 2 WHERE aircraft = 1 AND dep_time >= 06:00
UPDATE flights SET aircraft = 1 WHERE aircraft = 2 AND dep_time >= 06:00
COMMIT();
据我所知,第二个更新语句将看到第一个语句中更新的值,这将使一切变得混乱。有没有办法让两个UPDATE语句都使用事务启动时存在的值?如果没有,有没有人有更好的建议如何处理这个?
我希望的结果是:
flight aircraft dep_time
1 1 05:00
2 2 06:00
3 2 07:00
4 2 05:00
5 1 06:00
6 1 07:00
谢谢!如果不清楚,我道歉......
答案 0 :(得分:0)
您需要在表中添加唯一列(通常它将具有名称id
并且是无符号的大型int auto_increment类型)
然后,只要每行都有唯一的ID,您就可以根据需要交换行。
答案 1 :(得分:0)
这根本不是关于交易的,而是关于使用UPDATE来交换价值(无论是否在单个交易中)。交易不会像你的问题暗示的那样“保存交易开始时存在的数据”:你似乎误解了它们的用途。您可以COMMIT
或ROLLBACK
正在进行的事务,但您不能编写明确引用当前事务数据库与事务前数据库数据的查询。
如果您需要在给定时间点“保存”数据,则可以将其复制到临时表,或者复制到当前表中为此(临时存储)目的而创建的其他列。
但是,更简单的解决方案是:如果您可以将整个事物编写为单个更新语句,那么您将不会遇到任何问题,因为每行只会被处理一次单UPDATE
,例如:
UPDATE flights SET aircraft = IF(aircraft=1,2,1) WHERE (aircraft = 1 OR aircraft = 2) AND dep_time >= 06:00
在这种特殊情况下,应解决您的问题。
(也就是说,请注意,如果您要更新主键或唯一键,行仍然会逐个更新,这可能会导致重复键错误,即使 final 更新的结果将没有任何。所以在这种情况下,您可能必须使用ORDER BY
仔细订购更新,否则您可能必须临时插入虚拟值并使用多个UPDATE
语句,你现在的方式。)