【问题标题】:MySQL `timestamp` to be updated even with same column valueMySQL `timestamp` 即使使用相同的列值也会更新
【发布时间】:2017-06-13 19:55:25
【问题描述】:

我正在对我的一张表使用时间戳列,并使用自动更新功能。这是我的表架构:

mysql> desc user_rides;
+------------+--------------+------+-----+-------------------+-----------------------------+
| Field      | Type         | Null | Key | Default           | Extra                       |
+------------+--------------+------+-----+-------------------+-----------------------------+
| id         | int(11)      | NO   | PRI | NULL              | auto_increment              |
| user_id    | int(11)      | NO   | MUL | NULL              |                             
| ride_cnt   | int(11)      | YES  |     | NULL              |                             |
| created_at | timestamp    | NO   |     | CURRENT_TIMESTAMP |                             |
| updated_at | timestamp    | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+------------+--------------+------+-----+-------------------+-----------------------------+
5 rows in set (0.02 sec)

我期待的是,

  • created_at 列与时间一起初始化,行被创建和
  • updated_at 列与created_at 相同,并且在任何列(基本上是ride_cnt)更新时也会更新。

这很好用。

但我也期望updated_at 会更新,即使ride_cnt 具有相同的值。这样我就可以跟踪上次获取该行的值的时间,并且可以忽略以进一步运行。

例如:

ride_cnt = 0 的行将使用我们运行更新的最近时间进行更新。这样可以在很长一段时间内忽略行以重新初始化。

有什么方法可以在不手动传递时间戳的情况下实现这一点?

编辑:

这里发生了什么,

mysql> insert into user_ride set user_id=7445, user_ride=0;
Query OK, 1 row affected (0.01 sec)

mysql> insert into user_ride set user_id=7009, user_ride=2;
Query OK, 1 row affected (0.00 sec)

mysql> select * from user_ride;
+----+---------+-----------+---------------------+---------------------+
| id | user_id | user_ride | created_at          | updated_at          |
+----+---------+-----------+---------------------+---------------------+
|  1 |    7445 |         0 | 2017-06-13 10:44:05 | 2017-06-13 10:44:05 |
|  2 |    7009 |         2 | 2017-06-13 10:44:18 | 2017-06-13 10:44:18 |
+----+---------+-----------+---------------------+---------------------+
2 rows in set (0.00 sec)

mysql> update user_ride set user_ride=0 where id=1;
Query OK, 0 rows affected (0.01 sec)
Rows matched: 1  Changed: 0  Warnings: 0

mysql> select * from user_ride;
+----+---------+-----------+---------------------+---------------------+
| id | user_id | user_ride | created_at          | updated_at          |
+----+---------+-----------+---------------------+---------------------+
|  1 |    7445 |         0 | 2017-06-13 10:44:05 | 2017-06-13 10:44:05 |
|  2 |    7009 |         2 | 2017-06-13 10:44:18 | 2017-06-13 10:44:18 |
+----+---------+-----------+---------------------+---------------------+
2 rows in set (0.00 sec)

mysql> update user_ride set user_ride=1 where id=1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from user_ride;
+----+---------+-----------+---------------------+---------------------+
| id | user_id | user_ride | created_at          | updated_at          |
+----+---------+-----------+---------------------+---------------------+
|  1 |    7445 |         1 | 2017-06-13 10:44:05 | 2017-06-13 10:45:26 |
|  2 |    7009 |         2 | 2017-06-13 10:44:18 | 2017-06-13 10:44:18 |
+----+---------+-----------+---------------------+---------------------+
2 rows in set (0.00 sec)

【问题讨论】:

  • 你试过触发器吗?
  • 如果您使用记录中已有的相同值进行更新,更新仍会发生,并且您当前的时间戳仍应更新。我在这里错过了什么吗?
  • @TimBiegeleisen,即使我假设相同,但事实并非如此。添加示例。
  • @Namphibian,由于其他复杂性,不想添加触发器。
  • @avisheks 我放弃了我上面的评论。如果数据不需要更改,MySQL 会更新一行。

标签: mysql timestamp sql-timestamp


【解决方案1】:

我想提请注意您在上述情况下的第一次更新:

mysql> update user_ride set user_ride=0 where id=1;
Query OK, 0 rows affected (0.01 sec)
Rows matched: 1  Changed: 0  Warnings: 0

我们可以看到有匹配的行,但实际上没有更新。这样做的原因是更新不会导致数据实际发生变化。因此,updated_at 时间戳的ON UPDATE 子句从未生效。我可以为您的问题提供两种解决方法。第一个,可能是性能最高的,将在更新期间手动将updated_at 列设置为当前时间戳。因此,从上面的示例中,您将使用它:

update user_ride set user_ride = 0, updated_at = CURRENT_TIMESTAMP where id=1;

这应该会触发行的实际更新,因为自上次更新以来时间戳已更改。

另一种解决方法是找到一种方法来确保每次更新都会更改给定记录中的某些数据。然后,将始终应用 ON UPDATE 子句。

这似乎是一个限制,但我猜如果基础数据本身没有变化,MySQL 不会认为记录发生了变化。

这个问题有点像这个问题的重复:

How to Force UPDATE of MySQL Record When Nothing Is Changing

但是,由于 SO 对这个问题的报道如此之少,我认为这个答案可能对遇到同样问题的其他人有用。

【讨论】:

  • 谢谢蒂姆,我想知道这是否可以通过任何方式隐式实现。手动传递时间戳会是我能想到的更好的解决方案,但如果我们不能利用 mysql 的自动更新功能,那就不好了。在这种情况下添加ON UPDATE 子句没有任何意义:)
  • @avisheks 是的,ON UPDATE的意思。这意味着记录中的实际数据发生了变化,并且在很多情况下您只想更改发生这种情况时的时间戳。只是在您的特定情况下,这不是您想要的。
  • 就是这样,在我的情况下没有。
【解决方案2】:

添加触发器。

CREATE TRIGGER user_ride_bu
BEFORE UPDATE ON user_ride
FOR EACH ROW
SET NEW.updated_at = NOW();

(对于那些想知道DELIMITER 指令在哪里的人,当触发器有一个简单的语句时,它们就不需要了)。

【讨论】:

  • 支持分隔符,但 OP 不能使用触发器。见 cmets。
猜你喜欢
  • 2013-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-24
  • 2011-04-30
  • 2020-07-24
  • 2011-12-04
  • 1970-01-01
相关资源
最近更新 更多