目录
1. 整数类型(精确值)
1.1. MySQL
1.1.1. 签名和无符号
1.2. Oracle
2. 定点类型(精确值)——DECIMAL、NUMERIC
3. 浮点类型(近似值)——FLOAT、DOUBLE
4. 日期和时间数据类型
4.1. date
4.2. datetime
4.3. timestamp
5. 字符类型
6. clob 大字段
7. INTERVALDS
7.1. 需要提醒大家的是:
7.1.1. Oracle 的 timestamp
7.1.2. Oracle的 INTERVALDS
7.2. 转换代码
8. 参考文章
最近在做 Oracle 数据库 往 Maria 数据库的迁移工作,在此记录一下 Oracle 与 Maria 数据结构的差异。
MySQL 支持 SQL 标准整数类型 INTEGER
(或INT
)和 SMALLINT
. 作为标准的扩展,MySQL 还支持整数类型 TINYINT
、MEDIUMINT
和 BIGINT
. 下表显示了每种整数类型所需的存储空间和范围。
类型 | 存储(字节) | 签名的最小值 | 最小值无符号 | 签名的最大值 | 最大值无符号 |
---|---|---|---|---|---|
TINYINT |
1 | -128 |
0 |
127 |
255 |
SMALLINT |
2 | -32768 |
0 |
32767 |
65535 |
MEDIUMINT |
3 | -8388608 |
0 |
8388607 |
16777215 |
INT |
4 | -2147483648 |
0 |
2147483647 |
4294967295 |
BIGINT |
8 | -263 |
0 |
263-1 |
264-1 |
上图有一个令人疑惑的地方,为什么有 签名的最小值 和 签名的最大值 这一对之外,还有 最小值无符号 和 最大值无符号 这一对呢?
我们以 TINYINT 为例,
正常认为的取值范围就是 -128到127。
我们看上图中发现,这个范围正好是 签名 的取值范围。其实这个签名翻译不算准确,准确的说法应该是 有符号的 。这样就匹配了。因为官方的说法就是:
那这究竟是什么意思呢?
Signed 分正负数,Unsigned 只有正数。
如果是 Unsigned 的,那么存储需要1个字节,那就是8位,等于是最小值是0,最大值是 255。换成二进制是8个0和8个1。
00000000 11111111
8个0是0,8个1是255。
但是如果计算机想表示负数呢?
那么8位数字的最高位就会变成符号位,0代表正数,1代表负数,那么它的范围就变成:
二进制: 10000000 - 01111111
十进制: -128 至 127
不过我们在数据库中存储的数据,肯定存在负数的情况,我们的村粗都是是 Signed 的,也就是有-128 至 127的。
所以我们只需要看 签名的最小值 和 签名的最大值 即可。
Oracle 没有对应的证书类型,它只有数值类型:
number数据类型
number数据类型可以存储正数,负数,0,定点数和精度为38为的浮点数,该数据类型格式为
number(p, s)
其中,p表示精度,表示有效的位数,在1~38之间。有效数:从左边第一个不为0的数算起,小数点和负号不计入有效数。
s为范围,表示小数点右边数字的位数,它在- 84 ~ +127之间。
规则:
精确到小数点右边S位也就是小数部分,超出的四舍五入。
如果精确后的有效位数小于等于p,则正确,否则报错。
解读:
p代表最后的位数;
S代表小数点后的位数。
如果我们我们定义一个数值:
NUMBER(3, 3)
因为小数点后要三位,而精度也是三位,那么这个数字就只能是0和小于1的数字,不然会报错。
负数范围也是如此,必须是大于-1小于等于0的数字。
如果我们我们定义一个数值:
NUMBER(3, 4)
因为小数点后要4位,而精度是三位,那么这个数据类型虽然可以创建,但是不能插入任何数据,除了0。0插入之后也会变为,0.0000。但是,貌似好像没有人这么做吧,也许极少数场景会需要把!
综述:
p一般是大于等于s的。
结论
Oracle 的 number 数据类型不仅支持整型,还支持浮点数,也就是带小数点的数字。
只能存储是数字。
如果我整数,则小数位数是0,也可以不写,只写精度p。
DECIMAL
和NUMERIC
类型存储精确的数字数据值 。当保持精确的精度很重要时使用这些类型,例如货币数据。在 MySQL 中,NUMERIC
被实现为DECIMAL
,所以以下关于DECIMAL
同样适用于 NUMERIC。
DECIMAL(5, 2)
在本例中,5
是精度, 2
是比例。精度表示为值存储的有效位数,小数位数表示可以存储在小数点后的位数。
标准 SQL 要求DECIMAL(5,2)
能够存储任何 5 位和 2 位小数的值,因此salary
列中可以存储的值范围从-999.99
到 999.99。
其实我们看到,这个是和 Oracle 的 number 数据类型是一样的。
和类型表示FLOAT
近似DOUBLE
数值数据值。MySQL 对单精度值使用四个字节,对双精度值使用八个字节。
具体情况参考官网:浮点类型(近似值)
Oracle 没有浮点数这个概念。
用于表示时间值的日期和时间数据类型是 DATE、 TIME、 DATETIME、 TIMESTAMP和 YEAR。每种时间类型都有一个有效值范围,以及一个“零”值,当您指定 MySQL 无法表示的无效值时,可以使用该值。TIMESTAMP和 类型具有特殊的DATETIME自动更新行为,在 第 11.2.6 节,“TIMESTAMP 和 DATETIME 的自动初始化和更新”中进行了描述。
Oracle 的 date 类型 可以存储时间,例如时间:2022-05-04 11:45:37
MySQL 不可以,只能显示日期,不显示时间,即2022-05-04
即使我们给它设置时间,它也会自动截取的:
update TEST1 set COMMONT2 = CURRENT_TIMESTAMP;
结果如下:
我们可以看到,时间没有显示。
MySQL有 datetime,Oracle没有这个数据类型。
mysql的 datetime 对应 Oracle的 date。
Oracle的 DATE类型,7字节存储,可表示日期和时间,支持范围是
[-4712-01-01 00:00:00] 至 [9999-12-31 23:59:59]
MySQL的 DATATIME:占8字节存储,可表示日期和时间,支持范围是
[1000-01-01 00:00:00] 至 [9999-12-31 23:59:59]
两个数据库都有 timestamp 数据类型,两者有一些区别。
mysql 的 timestamp:
精确到小数秒多少位,可以是 0 to 9,缺省是6。mysql时间范围是:
1970-01-01 00:00:01.000000 到 2038-01-19 03:14:07.999999
因为他们使用了time这一32位数字来表示时间,这就是著名的2038年问题。
支持自动时区转换。
如果表中包含TIMESTAMP的列,那么其建表语句有可能被系统篡改,取决于MySql的版本和参数设置。
当MySQL参数time_zone=system时,高并发可能会引起CPU使用率暴涨,系统响应变慢甚至假死。
如果存入超过范围的时间,在非严格状态下,MySql不会报错,反而会插入'0000-00-00 00:00:00'。
高并发环境下并不适合使用TIMESTAMP。
时间范围并不是强校验的。如果我们尝试往MySql中插入超过TIMESTAMP可表示的时间范围的值,MySql在非严格模式下并不会报错,仅会产生一个warning。
最大范围是timestamp(6),但是可以放9位小数,具体原因,待查。
Maria的timestamp不能为空,如果不设置值会默认给当前时间,比如插入一条数据时。
所以,目前 mysql 和 Maria 数据库,日期时间格式建议尽量不要使用 timestamp。
Oracle 的 timestamp 就是正常的日期时间,可以带毫秒数,不会自动赋值。比如我们建表时,希望更新时间这个字段随着每次数据的新增和修改都会自动添加和修改这个字段,那我们的 Oracle 这个字段不会自动实现,需要我们自己去实现。
但是 mysql 会自动添加时间。
mysql的分为 varchar 和 char,Oracle 不但有 varchar 和 char,还有 varchar2,nvarchar, nvarchar2。
mysql 定义该数据类型为:
name VARCHARACTER(30)
Oracle 也一样。至于varchar2,nvarchar, nvarchar2 的定义方式也一样,具体差异可以自行百度,这里只告诉大家一点,如果你做Oracle迁移到 mysql 或者Maria,那么Oracle的几种字符类型,你都可以使用 varchar来转换。
其实 mysql 也有nvarchar类型,但是是一个保留字,你这么定义不会错,但是系统会自动给你转化为 varchar。
Oracle 的大字段类型是 clob,它存储的其实就是字符串,源文字是什么,它就存储什么。
对应的 mysql 的数据类型 可以使用 LONGTEXT 来存储,当然使用varchar也可以,但是小心varchar的存储范围不足,所以建议使用 LONGTEXT 。
在 mysql 中还有一个大字段类型,blob,它的存储是二进制字节码,和clob还是不一样的。如果你在里面输入,你好,那么显示的就会是乱码,但是如果你使用查看器的话发现还是 你好 。
这个是Oracle独有的数据类型,意思是时间间隔的意思,显示到数据库一般是:
INTERVAL DAYE TO SECOND
这里面会有一定的数字来做限制,我们取一个真实定义的类型来看看。
"COMMONT9" INTERVAL DAY (3) TO SECOND (6)
什么意思呢?
意思是,这是一个时间间隔,天的精度为3位数,也就是最大999天,秒的小数部分精度为6位数。此时,不但有天和秒,还会有时分。具体数据如:
+123 12:11:19.123456
在mysql和Maria中没有这个数据类型,我们可以使用varchar来接收或者转换。
此时如果使用Maria的varchar来表示,长度为:1+3+1+8+1+6=20,那么varchar的长度可以设置为20,或者稍微大一点。
注意:
这是我们在数据库中定义的类型,但是我们查询到数据之后拿什么来接收呢?
在mysql中,我们直接使用 String 接收没问题。但是在 Oracle 中,是不可以的,它有一个专门接收的类型:
INTERVALDS
至此,关于 Oracle 和MySQL的数据类型之间的差异我们统计完了,万一漏万,不足之处,烦请谅解!
对比情况参见下图:
查询到数据后接收的类型是
oracle.sql.TIMESTAMP
而不是
java.sql.Timestamp
这个需要你自行做转换。
mysql没有这个数据类型,需要我们自行转换。
while (oracleResultSet.next()) {
ResultSetMetaData metaData = oracleResultSet.getMetaData();
++count;
for (int i = 1; i <= columnCount; i++) {
Object object = oracleResultSet.getObject(i);
String columnTypeName = metaData.getColumnTypeName(i);
if ("TIMESTAMP".equals(columnTypeName) && object != null) {
object = convertOracleTIMESTAMP2JavaTimestamp(object);
}
if ("INTERVALDS".equals(columnTypeName) && object != null) {
object = convertOracleINTERVALDS2JavaString(object);
}
mariaPs.setObject(i, object);
}
}
convertOracleTIMESTAMP2JavaTimestamp 方法:
private static Timestamp convertOracleTIMESTAMP2JavaTimestamp(Object object) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class> clazz = object.getClass();
Method method = clazz.getMethod("timestampValue");
return (Timestamp) method.invoke(object);
}
convertOracleINTERVALDS2JavaString 方法:
private static String convertOracleINTERVALDS2JavaString(Object object) throws
NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class> clazz = object.getClass();
Method method = clazz.getMethod("toString");
return (String) method.invoke(object);
}
MySQL 官方参考手册
关于C语言中signed 和unsigned value