媒介
在日常使用中,很多人都会打仗和使用不只一种数据库,碰到最常见的题目就是各数据库之间的行为表现不一致,包括但不限于数据类型差异、语法差异、函数差异等等。尤其在数据库迁移的时候,这样的题目尤为显着。那为什么会有这样的差异呢?既然有SQL尺度,为什么各大数据库还是会有行为差异呢?
在数据库的使用过程中,我也碰到了这样的题目,那便来说说自己的一点见解。
尺度是什么? 什么是尺度? 最多人使用的做法就是尺度,不要削足适履。 最终呈现给用户的,一定是具体大量使用需求的功能聚集。而对于各大数据库来说,受限于自身的历史、架构和技术门路,一些功能的出现,总是团结着当时的某些业务场景的,这就导致最终呈现的形式会有差异。而这种差异是应该被明白的,不能因此而忽略各大数据库的优点。
最近在使用条件表达式COALESCE的时候,发现这种差异尤为显着,类似的使用还有CASE、NVL、IF、IFNULL、NULLIF等。
调用方式 | Oracle | Teradata | MySQL | PostgreSQL | GaussDB(DWS) | COALESCE(expr1,expr2...) | √ | √ | √ | √ | √ | CASE... result_n | √ | √ | √ | √ | √ | NVL(expr1,expr2) | √ | √ | | | √ | IF(bool_value,expr1,expr2) | | | √ | | | IFNULL(expr1,expr2) | | | √ | | | NULLIF(expr1,expr2) | √ | √ | √ | √ | √ | 接下来就以COALESCE为例,看下各数据库之间的差异表现。
1、回首下COALESCE的定义
- COALESCE(expr1, expr2, ..., exprn)
复制代码 COALESCE返回它的第一个非NULL的参数值。如果参数都为NULL,则返回NULL。它常用于在表现数据时用缺省值替换NULL。和CASE表达式一样,COALESCE只盘算用来判断结果的参数,即在第一个非空参数右边的参数不会被盘算。
COALESCE的语法图如下
2、各数据库的差异表现
COALESCE的差异表现为入参类型和返回值类型,以下分别验证Oracle、Teradata、MySQL、PostgreSQL、GaussDB(DWS)数据库的表现结果。
(1)Oracle
- -- number + char
- SQL> select coalesce(123,'456') from dual;
- select coalesce(123,'456') from dual
- *
- 第 1 行出现错误:
- ORA-00932: 数据类型不一致: 应为 NUMBER, 但却获得 CHAR
- -- char + number
- SQL> select coalesce('123',456) from dual;
- select coalesce('123',456) from dual
- *
- 第 1 行出现错误:
- ORA-00932: 数据类型不一致: 应为 CHAR, 但却获得 NUMBER
- -- number
- SQL> create table tmp1 as (select coalesce(100.01,456000) as col_1 from dual);
- 表已创建。
- SQL> select COLUMN_NAME,DATA_TYPE,DATA_LENGTH from user_tab_columns where TABLE_NAME='TMP1';
- COLUMN_NAME
- --------------------------------------------------------------------------------
- DATA_TYPE
- --------------------------------------------------------------------------------
- DATA_LENGTH
- -----------
- COL_1
- NUMBER
- 22
复制代码 Oracle对于COALESCE的入参要求比较严格,不支持入参混合类型,所有入参须为雷同类型。对于非数值类型,返回值类型雷同;对于数值类型,返回的类型为优先级较高的数值类型。
(2)Teradata
- -- number + char
- BTEQ -- Enter your SQL request or BTEQ command:
- select coalesce(123,'456') as a,type(a);
- *** Query completed. One row found. 2 columns returned.
- *** Total elapsed time was 1 second.
- a Type(a)
- ------------ --------------------------------------------------------------
- 123 VARCHAR(4) CHARACTER SET UNICODE
- -- char + number
- BTEQ -- Enter your SQL request or BTEQ command:
- select coalesce('123',456) b,type(b);
- *** Query completed. One row found. 2 columns returned.
- *** Total elapsed time was 1 second.
- b Type(b)
- ------------------ --------------------------------------------------------
- 123 VARCHAR(6) CHARACTER SET UNICODE
复制代码 Teradata对混合类型的支持较好,返回值的类型是所有入参的相容聚集类型且精度足够,具体情况视其所在语境而定。如果入参均为非字符类型,且类型雷同,则返回该类型;如果入参均为字符类型,返回值为长度最长的字符类型;如果前者参数是数值类型,先确定优先级最高的类型,隐式转换其他参数为该类型,再返回该类型;其他情况不支持。
(3)MySQL
- -- number + char
- mysql> select coalesce(123,'456');
- +---------------------+
- | coalesce(123,'456') |
- +---------------------+
- | 123 |
- +---------------------+
- 1 row in set (0.00 sec)
- mysql> create table t1 as select coalesce(123,'456');
- Query OK, 1 row affected (0.04 sec)
- Records: 1 Duplicates: 0 Warnings: 0
- mysql> desc t1;
- +---------------------+------------+------+-----+---------+-------+
- | Field | Type | Null | Key | Default | Extra |
- +---------------------+------------+------+-----+---------+-------+
- | coalesce(123,'456') | varchar(3) | NO | | | |
- +---------------------+------------+------+-----+---------+-------+
- 1 row in set (0.00 sec)
- -- char + number
- mysql> select coalesce('123',456);
- +---------------------+
- | coalesce('123',456) |
- +---------------------+
- | 123 |
- +---------------------+
- 1 row in set (0.00 sec)
- mysql> create table t2 as select coalesce('123',456);
- Query OK, 1 row affected (0.03 sec)
- Records: 1 Duplicates: 0 Warnings: 0
- mysql> desc t2;
- +---------------------+------------+------+-----+---------+-------+
- | Field | Type | Null | Key | Default | Extra |
- +---------------------+------------+------+-----+---------+-------+
- | coalesce('123',456) | varchar(3) | NO | | | |
- +---------------------+------------+------+-----+---------+-------+
- 1 row in set (0.00 sec)
复制代码 MySQL对混合类型的入参支持度很高,返回值的类型是所有入参的相容聚集类型,但具体情况视其所在语境而定。如果用在字符串语境中,则返回结果为字符串;如果用在数值语境中,则返回结果为十进制值、实值或整数值,且精度足够的类型。
(4)PostgreSQL
- -- number + char
- postgres=# create table t1 as select coalesce(123,'456');
- SELECT 1
- postgres=# \d+ t1
- 数据表 "public.t1"
- 栏位 | 类型 | Collation | Nullable | Default | 存储 | 统计目标 | 描述
- ----------+---------+-----------+----------+---------+-------+----------+------
- coalesce | integer | | | | plain | |
- -- char + number
- postgres=# create table t2 as select coalesce('123',456);
- SELECT 1
- postgres=# \d+ t2
- 数据表 "public.t2"
- 栏位 | 类型 | Collation | Nullable | Default | 存储 | 统计目标 | 描述
- ----------+---------+-----------+----------+---------+-------+----------+------
- coalesce | integer | | | | plain | |
复制代码 PostgreSQL对混合类型的入参提供了一定的支持,返回类型的选择却与Teradata和MySQL的相容规则差别。如果所有入参都是雷同的类型,而且不是字符串常量,那么剖析成这种类型;否则,优先转换为首个非字符串常量参数的类型;如果从给定的输入到所选的类型不能转换,则返回错误。
(5)GaussDB(DWS)
GaussDB(DWS)基于PostgreSQL进行拓展,对于COALESCE表达式有两种差别的表现,可以在CREATE DATABASE时通过指定选项DBCOMPATIBILITY进行选择。
- -- DBCOMPATIBILITY 默认选择 'ora'
- postgres=# show sql_compatibility;
- sql_compatibility
- -------------------
- ORA
- (1 row)
- -- number + char
- postgres=# create table t1 as select coalesce(123,'456');
- INSERT 0 1
- postgres=# \d+ t1
- Table "public.t1"
- Column | Type | Modifiers | Storage | Stats target | Description
- ----------+---------+-----------+---------+--------------+-------------
- coalesce | integer | | plain | |
- Has OIDs: no
- Distribute By: HASH(coalesce)
- Location Nodes: ALL DATANODES
- Options: orientation=row, compression=no
- -- char + number
- postgres=# create table t2 as select coalesce('123',456);
- INSERT 0 1
- postgres=# \d+ t2
- Table "public.t2"
- Column | Type | Modifiers | Storage | Stats target | Description
- ----------+---------+-----------+---------+--------------+-------------
- coalesce | integer | | plain | |
- Has OIDs: no
- Distribute By: HASH(coalesce)
- Location Nodes: ALL DATANODES
- Options: orientation=row, compression=no
复制代码 第1种情况的表现和PostgreSQL规则一致,属于对Oracle的拓展。
- -- DBCOMPATIBILITY 选择 'td'
- postgres=# create database tddb dbcompatibility = 'td';
- tddb=# show sql_compatibility;
- sql_compatibility
- -------------------
- TD
- (1 row)
- -- number + char
- postgres=# create table t1 as select coalesce(123,'456');
- INSERT 0 1
- postgres=# \d+ t1
- Table "public.t1"
- Column | Type | Modifiers | Storage | Stats target | Description
- ----------+------+-----------+----------+--------------+-------------
- coalesce | text | | extended | |
- Has OIDs: no
- Distribute By: HASH(coalesce)
- Location Nodes: ALL DATANODES
- Options: orientation=row, compression=no
- -- char + number
- postgres=# create table t2 as select coalesce('123',456);
- INSERT 0 1
- postgres=# \d+ t2
- Table "public.t2"
- Column | Type | Modifiers | Storage | Stats target | Description
- ----------+------+-----------+----------+--------------+-------------
- coalesce | text | | extended | |
- Has OIDs: no
- Distribute By: HASH(coalesce)
- Location Nodes: ALL DATANODES
- Options: orientation=row, compression=no
复制代码 第2种情况的表现基于对Teradata的拓展。入参类型完全雷同时,返回类型同入参类型;入参类型分类雷同时,返回类型为优先级较高的类型;入参类型分类差别时,支持数值、字符、常量字符串的混合类型,返回类型的优先级为依次为数值、字符、text;如果从给定的输入到所选的类型不能转换,则返回错误。
3、总结
用例 | Oracle | Teradata | MySQL | PostgreSQL | Gaussdb(ora) | Gaussdb(td) | COALESCE(123,'456') | 类型不一致 | varchar | varchar | integer | integer | text | COALESCE('123',456) | 类型不一致 | varchar | varchar | integer | integer | text | 从各数据库对COALESCE的返回值类型表现可以看出,基础功能表现一致,差异会集在入参类型的混合支持和返回值类型的规则选择。除了本文介绍的差异外,还有很多的差异点须要我们一点点去发掘、去吸收、去总结。对于每个开辟者,只有更好的了解数据库差异,才能更好的用好的数据库,制止在学习中、应用中、开辟中踩坑。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |