MySQL中同时存在创建和更新时间戳字段解决方法浅析
MySQL中同时存在创建和更新时间戳字段解决方法浅析
明确我的MySQL版本。
mysql> SELECT VERSION();
+------------+
| VERSION() |
+------------+
| 5.5.29-log |
+------------+
1 row in set (0.00 sec)
现在有这样的需求,一张表中有一个字段created_at记录创建该条记录的时间戳,另一个字段updated_at记录更新该条记录的时间戳。
我们尝试以下几个语句。
第一个,测试通过。
CREATE TABLE temp
(
id INT(11) PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(10),
updated_at timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
第二个,测试不通过。报ERROR 1293 (HY000)错误。(完整错误信息:ERROR 1293 (HY000): Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause)
CREATE TABLE temp
(
id INT(11) PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(10),
created_at timestamp NULL DEFAULT CURRENT_TIMESTAMP,
updated_at timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
MySQL 5.5.29中有这样的奇葩限制,不明白为什么。既然有这样的限制,那么只有绕道而行,现在尝试给出如下几种解决办法。
第一种,created_at使用DEFAULT CURRENT_TIMESTAMP或者DEFAULT now(),updated_at使用触发器。
具体解决方法如下:
1.temp表结构如下:
CREATE TABLE temp
(
id INT(11) PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(10),
created_at timestamp NULL DEFAULT CURRENT_TIMESTAMP,
updated_at timestamp NULL
);
2.插入测试数据:
mysql> INSERT INTO temp(name,created_at,updated_at) VALUES('robin',now(),now());
Query OK, 1 row affected (0.03 sec)
mysql> INSERT INTO temp(name,created_at,updated_at) VALUES('wentasy',now(),now());
Query OK, 1 row affected (0.01 sec)
mysql> SELECT * FROM temp;
+----+---------+---------------------+---------------------+
| id | name | created_at | updated_at |
+----+---------+---------------------+---------------------+
| 1 | robin | 2014-09-01 14:00:39 | 2014-09-01 14:00:39 |
| 2 | wentasy | 2014-09-01 14:01:11 | 2014-09-01 14:01:11 |
+----+---------+---------------------+---------------------+
2 rows in set (0.00 sec)
3.在temp上创建触发器,实现更新时记录更新时间;
delimiter |
DROP TRIGGER IF EXISTS tri_temp_updated_at;
CREATE TRIGGER tri_temp_updated_at BEFORE UPDATE ON temp
FOR EACH ROW
BEGIN
SET NEW.updated_at = now();
END;
|
delimiter ;
4.测试。
mysql> UPDATE temp SET name='robinwen' WHERE id=1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
#可以看到已经记录了第一条数据的更新时间
mysql> SELECT * FROM temp;
+----+----------+---------------------+---------------------+
| id | name | created_at | updated_at |
+----+----------+---------------------+---------------------+
| 1 | robinwen | 2014-09-01 14:00:39 | 2014-09-01 14:03:05 |
| 2 | wentasy | 2014-09-01 14:01:11 | 2014-09-01 14:01:11 |
+----+----------+---------------------+---------------------+
2 rows in set (0.00 sec)
第二种,created_at使用触发器,updated_at使用DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP或者DEFAULT now() ON UPDATE now();
具体解决方法如下:
1.temp表结构如下:
CREATE TABLE temp
(
id INT(11) PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(10),
created_at timestamp NULL,
updated_at timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
2.在temp上创建触发器,实现插入数据记录创建时间;
delimiter |
DROP TRIGGER IF EXISTS tri_temp_created_at;
CREATE TRIGGER tri_temp_created_at BEFORE INSERT ON temp
FOR EACH ROW
BEGIN
IF new.created_at IS NULL
THEN
SET new.created_at=now();
END IF;
END;
|
delimiter ;
3.插入测试数据:
mysql> INSERT INTO temp(name,created_at,updated_at) VALUES('robin',now(),now());
Query OK, 1 row affected (0.01 sec)
mysql> INSERT INTO temp(name,created_at,updated_at) VALUES('wentasy',now(),now());
Query OK, 1 row affected (0.01 sec)
mysql> SELECT * FROM temp;
+----+---------+---------------------+---------------------+
| id | name | created_at | updated_at |
+----+---------+---------------------+---------------------+
| 1 | robin | 2014-09-01 14:08:36 | 2014-09-01 14:08:36 |
| 2 | wentasy | 2014-09-01 14:08:44 | 2014-09-01 14:08:44 |
+----+---------+---------------------+---------------------+
2 rows in set (0.00 sec)
4.测试。
mysql> UPDATE temp SET name='robinwen' WHERE id=1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
#可以看到已经记录了第一条数据的更新时间
mysql> SELECT * FROM temp;
+----+----------+---------------------+---------------------+
| id | name | created_at | updated_at |
+----+----------+---------------------+---------------------+
| 1 | robinwen | 2014-09-01 14:08:36 | 2014-09-01 14:09:09 |
| 2 | wentasy | 2014-09-01 14:08:44 | 2014-09-01 14:08:44 |
+----+----------+---------------------+---------------------+
2 rows in set (0.00 sec)
第三种,created_at指定timestamp DEFAULT '0000-00-00 00:00:00',updated_at指定DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP或者timestamp DEFAULT now() ON UPDATE now();
具体解决方法如下:
1.temp表结构如下:
CREATE TABLE temp
(
id INT(11) PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(10),
created_at timestamp NULL DEFAULT '0000-00-00 00:00:00',
updated_at timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
2.插入测试数据:
mysql> INSERT INTO temp(name,created_at,updated_at) VALUES('robin',now(),now());
Query OK, 1 row affected (0.01 sec)
mysql> INSERT INTO temp(name,created_at,updated_at) VALUES('wentasy',now(),now());
Query OK, 1 row affected (0.01 sec)
mysql> SELECT * FROM temp;
+----+---------+---------------------+---------------------+
| id | name | created_at | updated_at |
+----+---------+---------------------+---------------------+
| 1 | robin | 2014-09-01 14:10:43 | 2014-09-01 14:10:43 |
| 2 | wentasy | 2014-09-01 14:10:57 | 2014-09-01 14:10:57 |
+----+---------+---------------------+---------------------+
2 rows in set (0.00 sec)
3.测试。
mysql> UPDATE temp SET name='robinwen' WHERE id=1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
#可以看到已经记录了第一条数据的更新时间
mysql> SELECT * FROM temp;
+----+----------+---------------------+---------------------+
| id | name | created_at | updated_at |
+----+----------+---------------------+---------------------+
| 1 | robinwen | 2014-09-01 14:10:43 | 2014-09-01 14:11:24 |
| 2 | wentasy | 2014-09-01 14:10:57 | 2014-09-01 14:10:57 |
+----+----------+---------------------+---------------------+
2 rows in set (0.00 sec)
第四种,更换MySQL版本,MySQL 5.6已经去除了此限制。
我们可以看下MySQL 5.5和5.6帮助文档对于这个问题的解释。
From the MySQL 5.5 documentation:
One TIMESTAMP column in a table can have the current timestamp as the default value for initializing the column, as the auto-update value, or both. It is not possible to have the current timestamp be the default value for one column and the auto-update value for another column.
Changes in MySQL 5.6.5:
Previously, at most one TIMESTAMP column per table could be automatically initialized or updated to the current date and time. This restriction has been lifted. Any TIMESTAMP column definition can have any combination of DEFAULT CURRENT_TIMESTAMP and ON UPDATE CURRENT_TIMESTAMP clauses. In addition, these clauses now can be used with DATETIME column definitions. For more information, see Automatic Initialization and Updating for TIMESTAMP and DATETIME.
我们确定下MySQL的版本。
mysql> SELECT VERSION();
+---------------------------------------+
| VERSION() |
+---------------------------------------+
| 5.6.20-enterprise-commercial-advanced |
+---------------------------------------+
1 row in set (0.00 sec)
我们把文首测试不通过的SQL语句在MySQL 5.6下执行,可以看到没有任何错误。
CREATE TABLE temp
(
id INT(11) PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(10),
created_at timestamp NULL DEFAULT CURRENT_TIMESTAMP,
updated_at timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
Query OK, 0 rows affected (0.28 sec)
接着我们插入测试语句,并作测试。
mysql> INSERT INTO temp(name) VALUES('robin');
Query OK, 1 row affected (0.07 sec)
mysql> INSERT INTO temp(name) VALUES('wentasy');
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM temp;
+----+---------+---------------------+---------------------+
| id | name | created_at | updated_at |
+----+---------+---------------------+---------------------+
| 1 | robin | 2014-09-01 15:05:57 | 2014-09-01 15:05:57 |
| 2 | wentasy | 2014-09-01 15:06:02 | 2014-09-01 15:06:02 |
+----+---------+---------------------+---------------------+
2 rows in set (0.01 sec)
mysql> UPDATE temp SET name='robinwen' WHERE id=1;
Query OK, 1 row affected (0.02 sec)
Rows matched: 1 Changed: 1 Warnings: 0
#可以看到已经记录了第一条数据的更新时间
mysql> SELECT * FROM temp;
+----+----------+---------------------+---------------------+
| id | name | created_at | updated_at |
+----+----------+---------------------+---------------------+
| 1 | robinwen | 2014-09-01 15:05:57 | 2014-09-01 15:06:45 |
| 2 | wentasy | 2014-09-01 15:06:02 | 2014-09-01 15:06:02 |
+----+----------+---------------------+---------------------+
2 rows in set (0.00 sec)
总结
本文介绍的方法归根结底,就两条,一是建表语句指定默认值和更新动作,二是使用触发器插入默认值和更新时间。面对当前无法更改的事实,只能采取折中的办法或者牺牲更多来弥补。还有一条值得注意的是,遇到问题多想想不同的解决办法,尽可能地列出所有可能或者可行的方案,这样一来让自己学到更多,二来可以锻炼思维的广度,三来多种方案可以弥补某种方案在特定环境下不可行的不足。
MySQL中同时存在创建和更新时间戳字段解决方法浅析的更多相关文章
- MySQL中同一时候存在创建和上次更新时间戳字段解决方法浅析
在写这篇文章之前.明白我的MySQL版本号. mysql> SELECT VERSION(); +------------+ | VERSION() | +------------+ | 5.5 ...
- MySQL中遇到的几种报错及其解决方法
MySQL中遇到的几种报错及其解决方法 1.[Err] 1064 - You have an error in your SQL syntax; check the manual that corre ...
- MySQL there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause同时创建多个更新当前时间戳字段 解决方法
问题重现 在写这篇文章之前,明确我的MySQL版本,MariaDB 或者你使用 MySQL 8 也会出现如下问题 MySQL 版本 现在有这样的需求,一张表中有一个字段created_at记录创建该条 ...
- 浅谈MySQL中优化sql语句查询常用的30种方法 - 转载
浅谈MySQL中优化sql语句查询常用的30种方法 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中使 ...
- c++连接mysql并提示“无法解析的外部符号 _mysql_server_init@12”解决方法&提示缺少“libmysql.dll”
课程作业要用c++连接mysql server,但是出现些小问题,经查阅资料已经解决,做一下笔记. 环境:vs2017, mysql版本是8.0.16-winx64. 设置项目属性 项目 - C ...
- 检索 COM 类工厂中 CLSID 为 {10020200-E260-11CF-AE68-00AA004A34D5} 的组件时失败,解决方法如下:
检索 COM 类工厂中 CLSID 为 {10020200-E260-11CF-AE68-00AA004A34D5} 的组件时失败,解决方法如下: 第 一步:首先将msvcr71.dll, SQLD ...
- Android SDK Manager 更新失败的解决方法
Android SDK Manager 更新失败的解决方法 原文地址 最近使用Android SDK Manager 更新Android SDK tools 发现经常更新失败,获取不到更新信息: Fe ...
- log4j中Spring控制台输出Debug级信息过多解决方法
log4j中Spring控制台输出Debug级信息过多解决方法 >>>>>>>>>>>>>>>>> ...
- universal image loader在listview/gridview中滚动时重复加载图片的问题及解决方法
在listview/gridview中使用UIL来display每个item的图片,当图片数量较多需要滑动滚动时会出现卡顿,而且加载过的图片再次上翻后依然会重复加载(显示设置好的加载中图片) 最近在使 ...
随机推荐
- spring eureka 启动过程
spring-eureka 在springCloud是类似于 zookeeper的存在,主要负责服务的注册发现. 1 由于是Servlet应用,所以Eureka需要通过servlet的相关监听器 ...
- 2014-11-2 NOIP模拟赛1
Noip2009 团结模拟赛如题目理解困难,请自行阅读或参考样例.内存限制均为 256MB,时间限制均为 1s.出题人不会 故意 在题目中设置陷阱,但请自己注意程序的正确性.IO 文件名(.in/.o ...
- 使用CCProxy代理遇到的问题
第一种:打开CCProxy后,客户端电脑无法连接上. 解决方案:主机是否开启了360里面的局域网隐藏,这个一定要关闭,否则客户端无法找到主机.另外一种情况,主机关闭局域网隐藏之后,一直遭受ARP攻击, ...
- 洛谷P4568 飞行路线
题目描述 \(Alice\)和\(Bob\)现在要乘飞机旅行,他们选择了一家相对便宜的航空公司.该航空公司一共在\(n\)个城市设有业务,设这些城市分别标记为\(0\)到\(n−1\),一共有\(m\ ...
- 黑马旅游网 url-pattern不加斜杠报错 java.util.concurrent.ExecutioException: org.apache.catalina.LifecycleException
- 【VueJS】sublime text3支持VueJS语法高亮显示插件vue-syntax-highlight
1. sublime text3支持VueJS语法高亮显示插件vue-syntax-highlightgithub地址: https://github.com/vuejs/vue-syntax-hig ...
- 安卓下点击a标签不跳转;点击a标签在手机真机上会调出手机键盘的解决办法
安卓下点击a标签不跳转的解决办法,是不用href做跳转的链接,改为用JS控制跳转 <a href="javascript:;" ontouchstart="wind ...
- 《SQL 进阶教程》 case:将已有编号方式转换为新的方式并统计
SQL 权威指南SQL 解惑在进行非定制化统计时,需要将已有编号方式转换为另外一种便于分析的方式进行统计需求 select case when name='哈尔滨' then '黑龙江' when n ...
- 微信小程序入门文档
一 基本介绍 微信专门为小程序开发了一个ide叫做微信开发者工具 最新一版的微信开发者工具,把微信公众号的调试开发工作也集成了进去,可以更换开发模式. https://mp.weixin.qq.com ...
- Linux —— GDB调试程序
调试实现 在可执行文件中加入源代码的信息,比如可执行文件中第几条机器指令对应源代码的第几行,但并不是把整个源文件嵌入到可执行文件中,所以在调试时必须保证gdb能找到源文件. 生成可执行文件命令: g+ ...