统一SQL支持解析和改写Oracle字符串串联运算符
【统一sql】:https://www.light-pg.com/docs/LTSQL/current/index.html
LightDB 统一SQL 是一款基于 Go 开发的 SQL 转换中间件,支持将 Oracle 常用 SQL 语法翻译转换为其他数据库的 SQL 。以主流数据库Oracle的SQL为基准,将SQL语句转换为其他信创数据库(LightDB、PostgreSQL、TDSQL、DM8、OceanBase、openGauss等)的SQL语句。目标是降低业务部门适配信创数据库的成本,让用户尽可能少地修改数据访问层代码,使基于Hibernate、JPA、MyBatis等框架的Java应用程序,基于oci、libmysqlclient、cres开发工具、hsdb的c/c++应用程序以及其它能够调用c函数的程序都能够直接切换到目标信创数据库,实现信创数据库之间的平滑迁移。
前言
串联运算符 || 用于连接字符串和 CLOB 数据类型的数据。使用串联运算符连接两个字符串后会得到另一个字符串。
Oracle中SQL操作符的优先级如下:
操作符 | 优先级 |
---|---|
+, - (正负符号), PRIOR, CONNECT_BY_ROOT, COLLATE | 1 |
*, / | 2 |
+, - (加减法), | 3 |
=, !=, <, >, <=, >= | 4 |
IS [NOT] NULL, LIKE, [NOT] BETWEEN, [NOT] IN, EXISTS, IS OF type | 5 |
NOT | 6 |
AND | 7 |
OR | 8 |
可以看出来串联运算符 || 和+, - (加减法),在同一优先级,所有要特别注意。在这里我们称Oracle为源库,转化的库为目标库。
Oracle2PostgreSQL ,Oracle2TDSQL-MySQL5.7
转化语法
目标端是PostgreSQL,TDSQL-MySQL5.7,将||转为concat函数
结果
通过统一sql转化之后的结果:
-- 转换前Oracle SQL:
select '成交价格高于前一日收盘价;成交价格:' || 2 * 1000.00 || '元,收盘价:' || null || '' || ' '|| 'end'|| '' FROM DUAL;
'成交价格高于前一日收盘价;成交价格:'||2*1000.00||'元,收盘价:'||NULL||''||''||'END'||''|
------------------------------------------------------------------+
成交价格高于前一日收盘价;成交价格:2000元,收盘价: end |
-- 转换后PostgreSQL/TDSQL-MySQL5.7:
SELECT concat(concat(concat(concat(concat(concat(concat('成交价格高于前一日收盘价;成交价格:', 2*1000.00), '元,收盘价:'), NULL), ''), ' '), 'end'), '');
concat |
-------------------------------------+
成交价格高于前一日收盘价;成交价格:2000.00元,收盘价: end|
Oracle2LightDB-Oracle ,Oracle2DM,Oracle2OceanBase-Oracle
转化语法
目标端是LightDB-Oracle,DM,OceanBase-Oracle,,将||转为||
结果
通过统一sql转化之后的结果:
-- 转换前Oracle SQL:
select '成交价格高于前一日收盘价;成交价格:' || 2 * 1000.00 || '元,收盘价:' || null || '' || ' '|| 'end'|| '' FROM DUAL;
'成交价格高于前一日收盘价;成交价格:'||2*1000.00||'元,收盘价:'||NULL||''||''||'END'||''|
------------------------------------------------------------------+
成交价格高于前一日收盘价;成交价格:2000元,收盘价: end |
-- 转换后LightDB-Oracle SQL:
SELECT ((((((('成交价格高于前一日收盘价;成交价格:'||2*1000.00)||'元,收盘价:')||NULL)||'')||' ')||'end')||'') FROM DUAL;
?column? |
----------------------------------+
成交价格高于前一日收盘价;成交价格:2000元,收盘价: end|
-- 转换后达梦 SQL/OceanBase-Oracle SQL:
SELECT '成交价格高于前一日收盘价;成交价格:'||2*1000.00||'元,收盘价:'||NULL||''||' '||'end'||'' FROM DUAL;
?column? |
----------------------------------+
成交价格高于前一日收盘价;成交价格:2000元,收盘价: end|
-- 转换前Oracle SQL:
select 1||2-3||2+1 from dual
1||2-3||2+1|
-----------+
93|
-- 转换后LightDB-Oracle SQL:
SELECT ((1||2)-3||2)+1 FROM dual
?column?|
--------+
93|
-- 转换后达梦 SQL:
select 1||2-3||2+1 from dual
1||2-3||2+1|
-----------+
1-13 |
-- 转换后OceanBase-Oracle:
select 1||2-3||2+1 from dual
1||2-3||2+1|
-----------+
93|
总结
-
目标库、源库串联运算符优先级不同,源库中串联运算符和加法、减法在同一级,而目标库DM、LightDB-Oracle中串联运算符和加法、减法不在同一级。所以DM中串联的字符串中含有加法或减法,两边数据库结果可能不一致,统一SQL中对LightDB-Oracle中进行括号优先级的处理。
-
方案中串联运算符会转化成concat函数的那种情况,转化的结果是字符串,字符串在源库和目标库的隐式转化范围不同,这个也需要注意