Oracle 与 TiDB 函数和语法差异对照
本文档提供了 Oracle 与 TiDB 的函数和语法差异对照,方便你根据 Oracle 函数查找对应的 TiDB 函数,了解 Oracle 与 TiDB 语法差异。
注意:
本文的内容是基于 Oracle 12.2.0.1.0 和 TiDB v5.4.0,其他版本可能存在差异。
函数对照表
下表列出了 Oracle 与 TiDB 部分函数的对照表。
函数 | Oracle 语法 | TiDB 语法 | 说明 | ||
---|---|---|---|---|---|
转换数据类型 | TO_NUMBER(key) TO_CHAR(key) |
CONVERT(key,dataType) |
TiDB 支持转换为下面类型:BINARY 、CHAR 、DATE 、DATETIME 、TIME 、SIGNED INTEGER 、UNSIGNED INTEGER 和 DECIMAL 。 |
||
日期类型转换为字符串类型 | TO_CHAR(SYSDATE,'yyyy-MM-dd hh24:mi:ss') TO_CHAR(SYSDATE,'yyyy-MM-dd') |
DATE_FORMAT(NOW(),'%Y-%m-%d %H:%i:%s') DATE_FORMAT(NOW(),'%Y-%m-%d') |
TiDB 的格式化字符串大小写敏感。 | ||
字符串类型转换为日期类型 | TO_DATE('2021-05-28 17:31:37','yyyy-MM-dd hh24:mi:ss') TO_DATE('2021-05-28','yyyy-MM-dd hh24:mi:ss') |
STR_TO_DATE('2021-05-28 17:31:37','%Y-%m-%d %H:%i:%s') STR_TO_DATE('2021-05-28','%Y-%m-%d%T') |
TiDB 的格式化字符串大小写敏感。 | ||
获取系统当前时间(精确到秒) | SYSDATE |
NOW() |
|||
获取当前时间(精确到微秒) | SYSTIMESTAMP |
CURRENT_TIMESTAMP(6) |
|||
获取两个日期相差的天数 | date1 - date2 |
DATEDIFF(date1, date2) |
|||
获取两个日期间隔月份 | MONTHS_BETWEEN(ENDDATE,SYSDATE) |
TIMESTAMPDIFF(MONTH,SYSDATE,ENDDATE) |
Oracle 中 MONTHS_BETWEEN() 函数与 TiDB 中 TIMESTAMPDIFF() 函数的结果会有误差。TIMESTAMPDIFF() 只保留整数月。使用时需要注意,两个函数的参数位置相反。 |
||
日期增加/减少 n 天 | DATEVAL + n |
DATE_ADD(dateVal,INTERVAL n DAY) |
n 可为负数。 |
||
日期增加/减少 n 月 | ADD_MONTHS(dateVal,n) |
DATE_ADD(dateVal,INTERVAL n MONTH) |
n 可为负数。 |
||
获取日期到日 | TRUNC(SYSDATE) |
CAST(NOW() AS DATE) DATE_FORMAT(NOW(),'%Y-%m-%d') |
TiDB 中 CAST 与 DATE_FORMAT 结果一致。 |
||
获取日期当月第一天 | TRUNC(SYSDATE,'mm') |
DATE_ADD(CURDATE(),interval - day(CURDATE()) + 1 day) |
|||
截取数据 | TRUNC(2.136) = 2 TRUNC(2.136,2) = 2.13 |
TRUNCATE(2.136,0) = 2 TRUNCATE(2.136,2) = 2.13 |
数据精度保留,直接截取相应小数位,不涉及四舍五入。 | ||
获取序列下一个值 | sequence_name.NEXTVAL |
NEXTVAL(sequence_name) |
|||
获取随机序列值 | SYS_GUID() |
UUID() |
TiDB 返回一个通用唯一识别码 (UUID)。 | ||
左/右外连接 | SELECT * FROM a, b WHERE a.id = b.id(+); SELECT * FROM a, b WHERE a.id(+) = b.id; |
SELECT * FROM a LEFT JOIN b ON a.id = b.id; SELECT * FROM a RIGHT JOIN b ON a.id = b.id; |
关联查询时,TiDB 不支持使用 (+) 实现左/右关联,只能通过 LEFT JOIN 或 RIGHT JOIN 实现。 |
||
NVL() |
NVL(key,val) |
IFNULL(key,val) |
如果该字段值为 NULL ,则返回 val 值,否则返回该字段的值。 |
||
NVL2() |
NVL2(key, val1, val2) |
IF(key is NULL, val1, val2) |
如果该字段值非 NULL ,则返回 val1 值,否则返回 val2 值。 |
||
DECODE() |
DECODE(key,val1,val2,val3) DECODE(value,if1,val1,if2,val2,...,ifn,valn,val) |
IF(key=val1,val2,val3) CASE WHEN value=if1 THEN val1 WHEN value=if2 THEN val2,...,WHEN value=ifn THEN valn ELSE val END |
|||
拼接字符串 a 和 b |
‘a’ \ |
\ | ‘b’ | CONCAT('a','b') |
|
获取字符串长度 | LENGTH(str) |
CHAR_LENGTH(str) |
|||
获取子串 | SUBSTR('abcdefg',0,2) = 'ab' SUBSTR('abcdefg',1,2) = 'ab' |
SUBSTRING('abcdefg',0,2) = '' SUBSTRING('abcdefg',1,2) = 'ab' |
|||
字符串在源字符串中的位置 | INSTR('abcdefg','b',1,1) |
INSTR('abcdefg','b') |
从字符串 'abcdefg' 第一个字符开始查询,返回 'b' 字符串第一次出现的位置。 |
||
字符串在源字符串中的位置 | INSTR('stst','s',1,2) |
LENGTH(SUBSTRING_INDEX('stst','s',2)) + 1 |
从字符串 'stst' 第一个字符开始查找,返回 's' 字符第二次出现的位置。 |
||
字符串在源字符串中的位置 | INSTR('abcabc','b',2,1) |
LOCATE('b','abcabc',2) |
从字符串 'abcabc' 第二个字符开始查询,返回 'b' 字符第一次出现的位置。 |
||
列合并为行 | LISTAGG(CONCAT(E.dimensionid,'---',E.DIMENSIONNAME),'***') within GROUP(ORDER BY DIMENSIONNAME) |
GROUP_CONCAT(CONCAT(E.dimensionid,'---',E.DIMENSIONNAME) ORDER BY DIMENSIONNAME SEPARATOR '***') |
将一列字段合并为一行并根据 *** 符号进行分割。 |
||
ASCII 值转化为对应字符 | CHR(n) |
CHAR(n) |
Oracle 中制表符 (CHR(9) )、换行符 (CHR(10) )、回车符 (CHR(13) ) 对应 TiDB 中的 CHAR(9) 、CHAR(10) 、CHAR(13) 。 |
语法差异
本节介绍 Oracle 部分语法与 TiDB 的差异。
字符串语法
Oracle 中字符串只能使用单引号 (‘’)。例如 'a'
。
TiDB 中字符串可以使用单引号 (‘’) 或双引号 (“”)。例如 'a'
或 "a"
。
NULL
与空字符串的区分
Oracle 中不区分 NULL
和空字符串 ''
,即 NULL
与 ''
是等价的。
TiDB 中区分 NULL
和空字符串 ''
。
INSERT
语句中读写同一张表
Oracle 支持 INSERT
语句中读写同一张表。例如:
INSERT INTO table1 VALUES (feild1,(SELECT feild2 FROM table1 WHERE...))
TiDB 不支持 INSERT
语句中读写同一张表。例如:
INSERT INTO table1 VALUES (feild1,(SELECT T.fields2 FROM table1 T WHERE...))
获取前 n 行数据
Oracle 通过 ROWNUM <= n
获取前 n 行数据。例如,ROWNUM <= 10
。
TiDB 通过 LIMIT n
获取前 n 行数据。例如,LIMIT 10
。Hibernate Query Language (HQL) 方式运行带 LIMIT
的 SQL 语句会出现错误,需要将 Hibernate 的运行方式改为 SQL 方式运行。
UPDATE
语句多表更新
Oracle 多表更新时不需要列出具体的字段更新关系。例如:
UPDATE test1 SET(test1.name,test1.age) = (SELECT test2.name,test2.age FROM test2 WHERE test2.id=test1.id)
TiDB 多表更新时需要在 SET
时把具体的字段更新关系都列出来。例如:
UPDATE test1,test2 SET test1.name=test2.name,test1.age=test2.age WHERE test1.id=test2.id
派生表别名
Oracle 多表查询时,派生表可以不起别名。例如:
SELECT * FROM (SELECT * FROM test)
TiDB 多表查询时,每一个派生出来的表都必须有一个自己的别名。例如:
SELECT * FROM (SELECT * FROM test) t
差集运算
Oracle 使用 MINUS
进行差集运算。例如:
SELECT * FROM t1 MINUS SELECT * FROM t2
TiDB 不支持 MINUS
,需要改写为 EXCEPT
进行差集运算。例如:
SELECT * FROM t1 EXCEPT SELECT * FROM t2
注释语法
Oracle 中注释语法为 --注释
,其中 --
后面不需要空格。
TiDB 中注释语法为 -- 注释
,其中 --
后面需要有一个空格。
分页查询
Oracle 分页查询时 OFFSET m
表示跳过 m
行数据,FETCH NEXT n ROWS ONLY
表示取 n
条数据。例如:
SELECT * FROM tables OFFSET 0 ROWS FETCH NEXT 2000 ROWS ONLY
TiDB 使用 LIMIT n OFFSET m
等价改写 OFFSET m ROWS FETCH NEXT n ROWS ONLY
。例如:
SELECT * FROM tables LIMIT 2000 OFFSET 0
ORDER BY
语句对 NULL
的排序规则
Oracle 中 ORDER BY
语句对 NULL
的排序规则:
ORDER BY COLUM ASC
时,NULL
默认被放在最后。ORDER BY COLUM DESC
时,NULL
默认被放在最前。ORDER BY COLUM [ASC|DESC] NULLS FIRST
时,强制NULL
放在最前,非NULL
的值仍然按声明顺序ASC|DESC
进行排序。ORDER BY COLUM [ASC|DESC] NULLS LAST
时,强制NULL
放在最后,非NULL
的值仍然按声明顺序ASC|DESC
进行排序。
TiDB 中 ORDER BY
语句对 NULL
的排序规则:
ORDER BY COLUM ASC
时,NULL
默认被放在最前。ORDER BY COLUM DESC
时,NULL
默认被放在最后。
下表是 Oracle 与 TiDB 中等价 ORDER BY
语句示例:
Oracle 中的 ORDER BY |
TiDB 中的 ORDER BY |
---|---|
SELECT * FROM t1 ORDER BY name NULLS FIRST; |
SELECT * FROM t1 ORDER BY name; |
SELECT * FROM t1 ORDER BY name DESC NULLS LAST; |
SELECT * FROM t1 ORDER BY name DESC; |
SELECT * FROM t1 ORDER BY name DESC NULLS FIRST; |
SELECT * FROM t1 ORDER BY ISNULL(name) DESC, name DESC; |
SELECT * FROM t1 ORDER BY name ASC NULLS LAST; |
SELECT * FROM t1 ORDER BY ISNULL(name), name; |