Oracle、Teradata和MySQL语法兼容性差异
GaussDB(DWS)支持Oracle(以下简称ORA)、Teradata(以下简称TD)和MySQL三种兼容模式,分别兼容Oracle、Teradata和MySQL语法,不同兼容模式下的语法行为有一些差异。
数据库兼容模式可以在创建数据库时指定(由DBCOMPATIBILITY参数控制),语法示例如下,具体参见CREATE DATABASE语法。
1 2 3 |
CREATE DATABASE td_compatible_db DBCOMPATIBILITY 'TD'; --创建兼容Teradata的数据库 CREATE DATABASE ora_compatible_db DBCOMPATIBILITY 'ORA'; --创建兼容Oracle的数据库 CREATE DATABASE mysql_compatible_db DBCOMPATIBILITY 'MYSQL'; --创建兼容MySQL的数据库 |
查询结果:
1 2 3 4 5 6 7 |
SELECT datname,datcompatibility FROM PG_DATABASE WHERE datname LIKE '%compatible_db'; datname | datcompatibility ---------------------+------------------ td_compatible_db | TD ora_compatible_db | ORA mysql_compatible_db | MYSQL (3 rows) |
兼容项 |
Oracle兼容 |
Teradata兼容 |
MySQL兼容 |
---|---|---|---|
数据类型date |
date会转为timestamp,包含年月日时分秒。 |
只有年月日。 |
只有年月日。 |
空串 |
只有null。 |
区分空串和null。 |
区分空串和null。 |
空串转数字 |
null。 |
转换为0。 |
转换为0。 |
超长字符自动截断 |
不支持。 |
支持(GUC参数td_compatible_truncation设置为ON)。 |
不支持。 |
varchar + int运算 |
转为bigint + int计算。 |
转为numeric + numeric计算。 |
转为bigint + int计算。 |
null拼接 |
非null对象与null拼接后返回非null对象。 例如,'abc'||null返回'abc'。 |
GUC参数behavior_compat_options增加strict_text_concat_td选项后,兼容TD行为,null类型拼接后返回null。 例如,'abc'||null返回null。 |
兼容MySQL行为,null类型拼接后返回null。 例如,'abc'||null返回null。 |
char(n)类型拼接 |
char(n)类型做拼接时移除右侧空格和占位。 例如,cast('a' as char(3))||'b'返回'ab'。 |
GUC参数behavior_compat_options增加bpchar_text_without_rtrim选项后,char(n)类型做拼接时,保留空格,并补足空格至指定的n长度。 当前不支持“比较字符串时忽略尾部空格”,拼接后结果如果存在尾部空格,进行比较时会对空格敏感。 例如,cast('a' as char(3))||'b'返回'a b'。 |
移除右侧空格和占位。 |
concat(str1,str2) |
返回所有非null字符串的连接。 |
返回所有非null字符串的连接。 |
入参中存在null时,返回结果为null。 |
left和right负数处理 |
返回除最后/前|n|个字符以外的所有字符。 |
返回除最后/前|n|个字符以外的所有字符。 |
返回空串。 |
lpad(string text, length int [, fill text]) rpad(string text, length int [, fill text]) |
通过填充字符fill(缺省为空格),把string填充到length长度,如果string已经比length长则将其尾部截断。如果fill为空串或者length为负数则返回null。 |
如果fill为空串且string长度小于length时,返回原字符串,如果length为负数则返回空串。 |
如果fill为空串且string长度小于length时,返回空串,如果length为负数则返回null。 |
substr(str, s[, n]) |
s = 0时,返回前n个字符。 |
s = 0时,返回前n个字符。 |
s = 0时,返回空串。 |
substring(str, s[, n]) substring(str [from s] [for n]) |
s = 0时,返回前n - 1个字符 s < 0时,返回前s + n - 1个字符 n < 0时,报错。 |
s = 0时,返回前n - 1个字符。 s < 0时,返回前s + n - 1个字符。 n < 0时,报错。 |
s = 0时,返回空串。 s < 0时,倒数第|s|个字符位置开始截取n个字符。 n < 0时,返回空串。 |
trim、ltrim、rtrim、btrim(string[,characters]) |
从字符串string的指定位置删除只包含characters中字符(缺省为空格)的最长的字符串。 |
从字符串string的指定位置删除只包含characters中字符(缺省为空格)的最长的字符串。 |
从字符串string的指定位置删除等于characters的字符串(缺省为空格)。 |
log(x) |
以10为底的对数。 |
以10为底的对数。 |
自然对数。 |
mod(x, 0) |
除数为0时返回x。 |
除数为0时返回x。 |
除数为0时报错。 |
to_char(date) |
入参最大值仅支持timestamp类型的最大值,不支持date类型的最大值;返回值类型为timestamp。 |
入参最大值仅支持timestamp类型的最大值,不支持date类型的最大值;返回值类型为date,且格式为'YYYY/MM/DD'(GUC参数convert_empty_str_to_null_td打开)。 |
入参最大值支持timestamp类型的最大值和date类型的最大值;返回值类型为date。 |
to_date, to_timestamp和to_number空串处理 |
返回null。 |
返回null(GUC参数convert_empty_str_to_null_td打开)。 |
to_date和to_timestamp返回null,to_number中参数为空串时,返回0。 |
last_day和next_day返回类型 |
timestamp类型。 |
timestamp类型。 |
date类型。 |
add_months返回类型 |
timestamp类型。 |
timestamp类型。 |
入参为date类型,返回date类型。 入参为timestamp类型,返回timestamp类型。 入参为timestamptz类型,返回timestamptz类型。 |
CURRENT_TIME CURRENT_TIME(p) |
获取当前事务的时间,返回值类型为timetz。 |
获取当前事务的时间,返回值类型为timetz。 |
获取当前语句执行时的时间,返回值类型为time。 |
CURRENT_TIMESTAMP CURRENT_TIMESTAMP(p) |
获取当前语句执行时的时间,返回值类型为timestamptz。 |
获取当前语句执行时的时间,返回值类型为timestamptz。 |
获取当前语句执行时的时间,返回值类型为timestamp。 |
CURDATE |
不支持。 |
不支持。 |
获取当前语句执行时的日期,返回值类型为date。 |
CURTIME(p) |
不支持。 |
不支持。 |
获取当前语句执行时的时间,返回值类型为time。 |
LOCALTIME LOCALTIME(p) |
获取当前事务的时间,返回值类型为time。 |
获取当前事务的时间,返回值类型为time。 |
获取当前语句执行时的时间,返回值类型为timestamp。 |
LOCALTIMESTAMP LOCALTIMESTAMP(p) |
获取当前事务的时间,返回值类型为timestamp。 |
获取当前事务的时间,返回值类型为timestamp。 |
获取当前语句执行时的时间,返回值类型为timestamp。 |
SYSDATE SYSDATE(p) |
获取当前语句执行时的时间,返回值类型为timestamp(0)。 |
获取当前语句执行时的时间,返回值类型为timestamp(0)。 |
获取当前系统的时间,返回值类型为timestamp(0)。此函数不可下推,建议用current_date代替。 |
now() |
获取当前事务时间,返回值类型为timestamptz。 |
获取当前事务时间,返回值类型为timestamptz。 |
获取语句执行的时间,返回值类型为timestamptz。 |
操作符'^' |
幂运算。 |
幂运算。 |
异或。 |
表达式greatest、least |
返回所有非null入参的比较结果。 |
返回所有非null入参的比较结果。 |
入参中存在null时,返回结果为null。 |
表达式case、coalesce、if、ifnull入参类型不同 |
报错。 |
兼容TD行为,支持数字和字符串之间的类型转换,比如coalesce参数输入int和varchar类型,解析成varchar类型。 |
兼容MySQL行为,支持其他类型和字符串之间的类型转换,比如coalesce参数输入date、int和varchar类型,解析成varchar类型。 |
反引号 |
不支持。 |
不支持。 |
区分MySQL的保留字与普通字符。 |
举例说明
以下以兼容Teradata模式为例运行SQL,如果需要查看Oracle、MySQL兼容模式下的行为差异,可以切换到对应的数据库ora_compatible_db、mysql_compatible_db,然后运行以下相同的SQL语句(表名相应替换为ora_table、mysql_table),即可体会上表所列举的不同兼容模式下的行为差异。
1 2 3 |
CREATE TABLE td_table(a INT,b VARCHAR(5),c date); INSERT INTO td_table VALUES(1,null,CURRENT_DATE); INSERT INTO td_table VALUES(2,'',CURRENT_DATE); |
区分空串和NULL,date类型只显示年月日
TD和MySQL模式下,区分空串和NULL,ORA模式下不区分空串和NULL,date类型会转为timestamp,包含年月日时分秒。
1
|
SELECT a, b, b IS NULL AS null, c FROM td_table; |
1
|
SELECT CURRENT_DATE; |
1
|
SELECT a, b, b IS NULL AS null, c FROM ora_table; |
1
|
SELECT CURRENT_DATE; |
1
|
SELECT a, b, b IS NULL AS null, c FROM mysql_table; |
1
|
SELECT CURRENT_DATE; |
空串转int,转为0
TD数据库不同于Oracle,Oracle将空串当作NULL进行处理,TD在将空串转换为数值类型的时候,默认将空串转换为0进行处理,因此查询空串会查询到数值为0的数据。
同样地,在TD兼容模式下,字符串转换数值的过程中,也会将空串默认转换为相应数值类型的0值进行处理。除此之外,' - '、' + '、' '这些字符串也都会在TD兼容模式下默认转换为0进行处理,但是小数点字符串' . '会报错。
1
|
SELECT b::int FROM td_table WHERE b = ''; |
1
|
SELECT b::int FROM ora_table WHERE b = ''; |
1
|
SELECT b::int FROM mysql_table WHERE b = ''; |
超长字符自动截断
- TD模式下,td_compatible_truncation参数设置为on时,将启用超长字符串自动截断功能,在后续的insert语句中(不包含外表的场景下),对目标表中char和varchar类型的列上插入超长字符串时,系统会自动按照目标表中相应列定义的最大长度对超长字符串进行截断。
- ORA和MySQL模式下,插入超长字符串会报错。
1 2 3 4 |
SHOW td_compatible_truncation; SET td_compatible_truncation = ON; INSERT INTO td_table VALUES(3,'12345678',CURRENT_DATE); SELECT * FROM td_table WHERE a = 3; |
参数td_compatible_truncation设置无效,插入超长字符会报错。
1 2 3 |
SHOW td_compatible_truncation; SET td_compatible_truncation = ON; INSERT INTO ora_table VALUES(3,'12345678',CURRENT_DATE); |
参数td_compatible_truncation设置无效,插入超长字符会报错。
1 2 3 |
SHOW td_compatible_truncation; SET td_compatible_truncation = ON; INSERT INTO mysql_table VALUES(3,'12345678',CURRENT_DATE); |
varchar + int运算,转为numeric + numeric计算
- TD模式下,varchar + int运算,转为numeric + numeric计算。
- ORA和MySQL模式下,转为bigint + int计算。
1
|
EXPLAIN VERBOSE SELECT b + a FROM td_table WHERE a = 3; |
1 2 |
INSERT INTO ora_table VALUES(3,'12345',CURRENT_DATE); EXPLAIN VERBOSE SELECT b + a FROM ora_table WHERE a = 3; |
1 2 |
INSERT INTO mysql_table VALUES(3,'12345',CURRENT_DATE); EXPLAIN VERBOSE SELECT b + a FROM mysql_table WHERE a = 3; |
null拼接返回null
- TD模式:GUC参数behavior_compat_options增加strict_text_concat_td选项,日期、时间、数字、字符串和null拼接均会返回null。
- ORA模式:非null对象与null拼接后返回非null对象。例如,'abc'||null返回'abc'。
- MySQL模式:兼容MySQL行为,null类型拼接后返回null。例如,'abc'||null返回null。
1 2 3 4 5 |
SET behavior_compat_options = 'strict_text_concat_td'; SELECT '2024-02-07 12:12:12'::TIMESTAMP || NULL; SELECT '12:12:12'::TIME || NULL; SELECT '12'::TINYINT || NULL; SELECT 'abc'::CHAR(10) || NULL; |
1
|
SELECT 'abc'::CHAR(10) || NULL; |
1
|
SELECT 'abc'::CHAR(10) || NULL; |
char(n)类型拼接
- TD模式下,GUC参数behavior_compat_options增加bpchar_text_without_rtrim选项,char(n)类型做拼接时,保留空格,并补足空格至指定的n长度。
- ORA和MySQL模式下,不保留空格。
例如,a后面带3个空格,强制转换成char(10)后,由于不足10个字符,则会用空格填充到10个字符,占用10个字节的存储空间,每个字节是8位,所以结果是80位。
1 2 |
SET behavior_compat_options = 'bpchar_text_without_rtrim'; SELECT bit_length('a '::char(10)); |
ORA和MySQL模式下,不保留空格,a只占了1个字符,占用1个字节的存储空间,所以结果是8。
1
|
SELECT bit_length('a '::char(10)); |
concat(str1,str2)
TD和ORA模式下,返回所有非null字符串的连接。MySQL模式下,入参中存在null时,返回结果为null。
1
|
SELECT concat(null, 'World!'); |
1
|
SELECT concat(null, 'World!'); |
left和right负数处理
TD和ORA兼容模式下,left和right函数分别返回除最后、最前|n|个字符以外的所有字符。MySQL模式下,返回空串。
1
|
SELECT left('abcde', -2); |
1
|
SELECT right('abcde', -2); |
1
|
SELECT left('abcde', -2); |
1
|
SELECT right('abcde', -2); |
lpad和rpad空串处理
- lpad和rpad函数在TD兼容模式下:如果fill为空串且string长度小于length时,返回原字符串。如果length为负数则返回空串。
- ORA模式下,都返回null。
- MySQL模式下,如果fill为空串且string长度小于length时,返回空串,如果length为负数则返回null。
1
|
SELECT lpad('a',7,''); |
1
|
SELECT lpad('a',-7,''); |
1
|
SELECT rpad('a',7,''); |
1
|
SELECT rpad('a',-7,''); |
ORA模式下,返回null。 rpad示例类似,不再赘述。
1
|
SELECT lpad('a',7,''); |
1
|
SELECT lpad('a',-7,''); |
1
|
SELECT lpad('a',7,''); |
1
|
SELECT lpad('a',-7,''); |
substr返回子串
substr(str, s[, n])函数在TD和ORA模式下,s = 0时,返回前n个字符。在MySQL模式下,返回空串。
1
|
SELECT SUBSTR('Hello, World!', 0, 5); |
1
|
SELECT SUBSTR('Hello, World!', 0, 5); |
substring返回子串
substring(str [from s] [for n])函数在TD和ORA模式下:
- s = 0时,返回前n - 1个字符。
- s < 0时,返回前s + n - 1个字符。
- n < 0时,报错。
MySQL模式下:
- s = 0时,返回空串。
- s < 0时,倒数第|s|个字符位置开始截取n个字符。
- n < 0时,返回空串。
示例1:s=0,n=5时返回'Hello, World!'前4个字符。
1
|
SELECT SUBSTRING('Hello, World!' FROM 0 FOR 5); |
示例2:s=-1,n=4时返回'Hello, World!'前两个字符。
1
|
SELECT SUBSTRING('Hello, World!' FROM -1 FOR 4); |
示例3:n=-1时直接报错。
1
|
SELECT SUBSTRING('Hello, World!' FROM -1 FOR -1); |
示例1:s=0,n=5时返回空串。
1
|
SELECT SUBSTRING('Hello, World!' FROM 0 FOR 5); |
示例2:s=-1,n=4时返回最后一个字符。
1
|
SELECT SUBSTRING('Hello, World!' FROM -1 FOR 4); |
示例3:n=-1时返回空串。
1
|
SELECT SUBSTRING('Hello, World!' FROM -1 FOR -1); |
btrim(string[,characters])
- TD和ORA模式下,从字符串string的指定位置删除只包含characters中字符(缺省为空格)的最长的字符串。
- MySQL模式下,从字符串string的指定位置删除等于characters的字符串(缺省为空格)。
1
|
SELECT BTRIM('xxHello Worldxx', 'xxz'); |
1
|
SELECT BTRIM('xxHello Worldxx', 'xxz'); |
log(x)对数运算
- TD和ORA模式下log(x)表示以10为底的对数,例如log(100)等同于log(10,100)。
- MySQL模式下表示自然对数,即以e为底(e≈ 2.71828)的对数,例如log(100)约等同于log(2.71828,100)。
1
|
SELECT log(100); |
1
|
SELECT log(100); |
mod(x,0)取模运算
TD和ORA模式下mod(x)除数为0时返回x。MySQL模式下报错。
1
|
SELECT mod(3,0); |
1
|
SELECT mod(3,0); |
to_char(date)
- TD模式下,入参最大值仅支持timestamp类型的最大值,不支持date类型的最大值;返回值类型为date,且格式为'YYYY/MM/DD'(GUC参数behavior_compat_options配置成convert_empty_str_to_null_td)。
- ORA模式下,入参最大值仅支持timestamp类型的最大值,不支持date类型的最大值;返回值类型为timestamp。
- MySQL模式下,入参最大值支持timestamp类型的最大值和date类型的最大值;返回值类型为date。
1
|
SELECT TO_CHAR(DATE '294276-12-31'); |
1
|
SELECT TO_CHAR(DATE '5874897-12-31'); |
1
|
SELECT TO_CHAR(DATE '294276-12-31'); |
1
|
SELECT TO_CHAR(DATE '5874897-12-31'); |
1
|
SELECT TO_CHAR(DATE '294276-12-31'); |
1
|
SELECT TO_CHAR(DATE '5874897-12-31'); |
to_date, to_timestamp和to_number空串处理
- TD兼容模式下,GUC参数behavior_compat_options配置成convert_empty_str_to_null_td参数,这些函数都返回null。
- ORA模式下,都返回null。
- MySQL模式下,to_date和to_timestamp返回null,to_number中参数为空串时,返回0。
1 2 3 4 |
SET behavior_compat_options = 'convert_empty_str_to_null_td'; --仅对TD模式生效。 SELECT TO_DATE(''); SELECT TO_TIMESTAMP(''); SELECT TO_NUMBER(''); |
1 2 3 |
SELECT TO_DATE(''); SELECT TO_TIMESTAMP(''); SELECT TO_NUMBER(''); |
last_day和next_day
- TD和ORA模式下,返回均为timestamp类型。
- MySQL模式下,返回date类型。
1
|
SELECT last_day(to_date('2024-02-07', 'YYYY-MM-DD')) AS cal_result; |
1
|
SELECT next_day(TIMESTAMP '2024-02-07 00:00:00','Sunday')AS cal_result; |
1
|
SELECT last_day(to_date('2024-02-07', 'YYYY-MM-DD')) AS cal_result; |
1
|
SELECT next_day(TIMESTAMP '2024-02-07 00:00:00','Sunday')AS cal_result; |
add_months时间加月
TD和ORA模式下,返回均为timestamp类型加月。
MySQL模式下:
- 入参为date类型,返回date类型。
- 入参为timestamp类型,返回timestamp类型。
- 入参为timestamptz类型,返回timestamptz类型。
1
|
SELECT add_months('2024-02-07'::date,3); |
1
|
SELECT add_months('2024-02-07'::date,3); |
1
|
SELECT add_months('2024-02-07 00:00:00',3); |
操作符'^'
- TD和ORA模式下,表示幂运算。
- MySQL模式下,表示异或。
1
|
SELECT 10^3; |
1
|
SELECT 10^3; |
表达式greatest、least
- TD和ORA模式下,返回所有非null入参的比较结果。
- MySQL模式下,入参中存在null时,返回结果为null。
1
|
SELECT greatest(1,2,3),least(1,2,3),greatest(1,null,3),least(1,null,3); |
1
|
SELECT greatest(1,2,3),least(1,2,3),greatest(1,null,3),least(1,null,3); |
case和coalesce表达式
- TD模式:兼容TD行为,支持数字和字符串之间的类型转换,比如coalesce参数输入int和varchar类型,解析成varchar类型。
- ORA模式:报错。
- MySQL模式:兼容MySQL行为,支持其他类型和字符串之间的类型转换,比如coalesce参数输入date、int和varchar类型,解析成varchar类型。
对于case和coalesce,在TD兼容模式下的处理:
- 如果所有输入都是相同的类型,并且不是unknown类型,那么解析成这种类型。
- 如果所有输入都是unknown类型则解析成text类型。
- 如果输入字符串(包括unknown,unknown当text来处理)和数字类型,那么解析成字符串类型,如果是其他不同的类型范畴,则报错。
- 如果输入类型是同一个类型范畴,则选择该类型的优先级较高的类型。
- 把所有输入转换为所选的类型。如果从给定的输入到所选的类型没有隐式转换则失败。
示例1:Union中的待定类型解析。这里,unknown类型文本'b'将被解析成text类型。
1
|
SELECT text 'a' AS "text" UNION SELECT 'b'; |
示例2:简单Union中的类型解析。文本1.2的类型为numeric,而且integer类型的1可以隐含地转换为numeric,因此使用这个类型。
1
|
SELECT 1.2 AS "numeric" UNION SELECT 1; |
示例3:转置Union中的类型解析。这里,因为类型real不能被隐含转换成integer,但是integer可以隐含转换成real,那么联合的结果类型将是real。
1
|
SELECT 1 AS "real" UNION SELECT CAST('2.2' AS REAL); |
示例4:TD模式下,coalesce参数输入int和varchar类型,那么解析成varchar类型,ORA模式下会报错。查看coalesce参数输入int和varchar类型的查询语句的执行计划如下。
1
|
EXPLAIN VERBOSE select coalesce(a, b) FROM td_table; |
TD模式下,coalesce参数输入int和varchar类型,解析成varchar类型,ORA模式下会报错。查看coalesce参数输入int和varchar类型的查询语句的执行计划如下。
1
|
EXPLAIN VERBOSE select coalesce(a, b) FROM ora_table; |
兼容MySQL行为,支持其他类型和字符串之间的类型转换,比如coalesce参数输入date、int和varchar类型,解析成varchar类型。