由一条create语句的问题对比mysql和oracle中的date差别 (r7笔记第26天)
今天开发的同事提交过来一个sql变更,在部署的时候发现了一个问题。
语句是一个简单的create语句
CREATE TABLE `test_user` (
`openid` varchar(64) NOT NULL,
`amount` varchar(11) DEFAULT 0,
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`openid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
报错内容为:
ERROR 1067 (42000) at line 1: Invalid default value for 'create_time'
首先这个看起来不是一个语法问题,部署使用的环境是5.5
这个时候手头有一套虚拟机测试环境,立马实验了一下,发现在5.6中竟然没有任何问题。
得到的信息如下
Query OK, 0 rows affected (0.13 sec)
所以这个问题引起了我的注意。
我做了下面几个测试,首先current_timestamp肯定是可用的。看看时间的情况。
select current_timestamp, current_timestamp();
+---------------------+---------------------+
| current_timestamp | current_timestamp() |
+---------------------+---------------------+
| 2015-11-23 18:31:25 | 2015-11-23 18:31:25 |
+---------------------+---------------------+
1 row in set (0.00 sec)
我们创建一个测试表来简单测试一下看看问题到底在哪里。
create table test(col1 datetime DEFAULT CURRENT_TIMESTAMP);
ERROR 1067 (42000): Invalid default value for 'col1'
看起来似乎是添加default值的时候出了问题。
> create table test(col1 datetime DEFAULT '');
ERROR 1067 (42000): Invalid default value for 'col1'
添加空值,也是不可以。
> create table test(col1 datetime DEFAULT '2015-11-23 18:31:25');
Query OK, 0 rows affected (0.02 sec)
添加一个固定的静态默认值,这样就可以了。
同时查看了一些文章,有的说不能添加默认值,这个说法应该是不成立的,只能说是不能添加动态的默认值。还有一种说法是default的动态默认值是在5.6.5才开始支持。
这部分内容在MySQL官方文档中也有说明。http://dev.mysql.com/doc/refman/5.0/en/data-type-defaults.html
那么这个问题还是需要解决,怎么解决呢。首先不可能为了这个操作先把数据库升级到5.6
那么解决方法就有两个。
一个是就是取消默认值,一个就是字段类型改为timestamp
那么问题来了,datetime和timestamp有啥区别和联系,如果没有记错还有一个类型时date,这三种数据类型有啥区别和关系
我们创建一个表,含有三个字段,datetime,timestamp,date
create table test(date1 datetime,date2 timestamp,date3 date);
然后插入三个值,来看看有什么差别。
mysql> insert into test values(current_date,current_timestamp,current_date);
Query OK, 1 row affected (0.00 sec)
mysql> select *from test;
+---------------------+---------------------+------------+
| date1 | date2 | date3 |
+---------------------+---------------------+------------+
| 2015-11-23 00:00:00 | 2015-11-23 23:21:35 | 2015-11-23 |
+---------------------+---------------------+------------+
可以看出datetime和timestamp其实是精确到秒的,date是精确到日。
那么datetime和timestamp有啥区别。
datetime和timestamp的存储占用空间不同,datetime占用8个字节,timestamp占用4个字节,所以说timestamp支 持的时间范围要窄一些。范围为:1970-01-01 08:00:01到2038-01-19 11:14:07 而datetime支持的时间范围则要大很多。1000-01-01 00:00:00 ~ 9999-12-31 23:59:59
简单来说,解放前的数据用timestamp就不合适了,而datetime则要更宽泛一些。
来简单验证一下。如果对timestamp列添加超过时间范围的值,则会报错。
mysql> insert into test values('2038-01-19 11:14:08','2038-01-19 11:14:08',current_date);
ERROR 1292 (22007): Incorrect datetime value: '2038-01-19 11:14:08' for column 'date2' at row 1
再次对timestamp插入最大值。
mysql> insert into test values('2038-01-19 11:14:08','2038-01-19 11:14:07',current_date);
mysql> select *from test;
+---------------------+---------------------+------------+
| date1 | date2 | date3 |
+---------------------+---------------------+------------+
| 2015-11-23 00:00:00 | 2015-11-23 23:21:35 | 2015-11-23 |
| 2038-01-19 11:14:08 | 2038-01-19 11:14:07 | 2015-11-23 |
+---------------------+---------------------+------------+
mysql> insert into test values('9999-12-31 23:59:59','2038-01-19 11:14:07',current_date);
Query OK, 1 row affected (0.00 sec)
对datetime插入最大值
mysql> insert into test values('9999-12-31 23:59:59','2038-01-19 11:14:07',current_date);
mysql> select *from test;
+---------------------+---------------------+------------+
| date1 | date2 | date3 |
+---------------------+---------------------+------------+
| 2015-11-23 00:00:00 | 2015-11-23 23:21:35 | 2015-11-23 |
| 2038-01-19 11:14:08 | 2038-01-19 11:14:07 | 2015-11-23 |
| 9999-12-31 23:59:59 | 2038-01-19 11:14:07 | 2015-11-23 |
+---------------------+---------------------+------------+
除此之外,datetime和timestamp还有一个区别,就是timestamp对于Insert,update操作会默认设置为current_timestamp
比如对datetime插入值,timestamp,date保留为空,结果如下:
mysql> insert into test(date1) values('2038-01-19 11:14:06');
mysql> select *from test;
+---------------------+---------------------+------------+
| date1 | date2 | date3 |
+---------------------+---------------------+------------+
| 2015-11-23 00:00:00 | 2015-11-23 23:21:35 | 2015-11-23 |
| 2038-01-19 11:14:08 | 2038-01-19 11:14:07 | 2015-11-23 |
| 9999-12-31 23:59:59 | 2038-01-19 11:14:07 | 2015-11-23 |
| 2038-01-19 11:14:06 | 2015-11-23 23:30:22 | NULL |
+---------------------+---------------------+------------+
4 rows in set (0.00 sec)
如果只对timestamp输入值,datetime和date为空,效果就大大不同
insert into test(date2) values('2038-01-19 11:14:06');
mysql> select *from test;
+---------------------+---------------------+------------+
| date1 | date2 | date3 |
+---------------------+---------------------+------------+
| 2015-11-23 00:00:00 | 2015-11-23 23:21:35 | 2015-11-23 |
| 2038-01-19 11:14:08 | 2038-01-19 11:14:07 | 2015-11-23 |
| 9999-12-31 23:59:59 | 2038-01-19 11:14:07 | 2015-11-23 |
| 2038-01-19 11:14:06 | 2015-11-23 23:30:22 | NULL |
| NULL | 2038-01-19 11:14:06 | NULL |
+---------------------+---------------------+------------+
这种类型的问题在oracle中就会是另外一种情况,oracle中对于timestamp的类型,精度要比date要高。
来简单做一个测试
SQL> create table test(date1 date,date2 timestamp);
Table created.
SQL> col name format a20
其实这个时候来查看timestamp,可以看到一个timestamp(6)字样的类型。
SQL> desc test
Name Null? Type
----------------------------------------- -------- ----------------------------
DATE1 DATE
DATE2 TIMESTAMP(6)
SQL> alter session set nls_date_format = 'yyyy-mm-dd hh24:mi:ss';
SQL> insert into test values(sysdate,sysdate);
SQL> col date2 format a30
DATE1 DATE2
------------------- ------------------------------
2015-11-23 23:03:35 23-NOV-15 11.03.35.000000 PM
如果插入systimestamp,结果会有一些差别。
SQL> insert into test values(systimestamp,systimestamp);
1 row created.
SQL> select *from test;
DATE1 DATE2
------------------- ------------------------------
2015-11-23 23:03:35 23-NOV-15 11.03.35.000000 PM
2015-11-23 23:05:08 23-NOV-15 11.05.08.378586 PM
其实在oracle中时间的类型还有很多,比如timestamp with timezone等等,支持的幅度也更大。
如果上面的问题在oracle中,是否可以支持动态的默认值呢,肯定可以,因为我们似乎已经习惯这么用了。
可以用下面的方式来指定。
SQL> alter table test modify(date1 default sysdate);
Table altered.
SQL> alter table test modify(date2 default systimestamp);
Table altered.
通过这些小测试也发现了时间的类型在mysql和oracle中还是有很大的差别,可能在数据类型的划分上,mysql划分的类型更多,数据类型非常多, 而oracle似乎一个Number就可以完全替代,其实内部也是做了很多的改进。通过对比来学习能够发现不少有意思的地方。
- MySQL 教程
- MySQL 安装
- MySQL 管理与配置
- MySQL PHP 语法
- MySQL 连接
- MySQL 创建数据库
- MySQL 删除数据库
- MySQL 选择数据库
- MySQL 数据类型
- MySQL 创建数据表
- MySQL 删除数据表
- MySQL 插入数据
- MySQL 查询数据
- MySQL where 子句
- MySQL UPDATE 查询
- MySQL DELETE 语句
- MySQL LIKE 子句
- mysql order by
- Mysql Join的使用
- MySQL NULL 值处理
- MySQL 正则表达式
- MySQL 事务
- MySQL ALTER命令
- MySQL 索引
- MySQL 临时表
- MySQL 复制表
- 查看MySQL 元数据
- MySQL 序列 AUTO_INCREMENT
- MySQL 处理重复数据
- MySQL 及 SQL 注入
- MySQL 导出数据
- MySQL 导入数据
- MYSQL 函数大全
- MySQL Group By 实例讲解
- MySQL Max()函数实例讲解
- mysql count函数实例
- MYSQL UNION和UNION ALL实例
- MySQL IN 用法
- MySQL between and 实例讲解
- 团体程序设计天梯赛-练习集 L1-039 古风排版
- 团体程序设计天梯赛-练习集 L1-027 出租
- MyBatis与设计模式的激情碰撞
- ES 慢查询日志收集实战总结
- 团体程序设计天梯赛-练习集 L1-016 查验身份证
- 团体程序设计天梯赛-练习集 L1-029 是不是太胖了
- 团体程序设计天梯赛-练习集 L1-031 到底是不是太胖了
- 进程监控工具 Procmon有Linux版本了
- 你凭什么说Spring会导致MyBatis的一级缓存失效!
- 团体程序设计天梯赛-练习集 L1-042 日期格式化
- 官方工具|MySQL Router 高可用原理与实战
- 团体程序设计天梯赛-练习集 L1-030 一帮一
- 团体程序设计天梯赛-练习集 L1-035 情人节
- 团体程序设计天梯赛-练习集 L1-038 新世界
- 团体程序设计天梯赛-练习集 L1-040 最佳情侣身高差