SPL:跨数据库移植 SQL

对于不同类型的数据库,即使是数据库都能支持的SQL查询,语法也大体相似,但仍然可能会有细微差别而不能通用。主要原因在于这些数据库各自的函数参数规则不同。

比如将字符串"2020-02-05"转换成日期, 不同数据库有不同的写法:

ORACLEselect TO_DATE('2020-02-05', 'YYYY-MM-DD') from USER;

SQLServerselect CONVERT(varchar(100), '2020-02-05', 23) from USER;

MYSQLselect DATE_FORMAT('2020-02-05','%Y-%m-%d') from USER;

如果希望应用在不同的数据库之间切换,就需要改写SQL语句,很麻烦。

SPL提供了sqltranslate函数,可以自动将SPL中简单SQL语句的函数翻译成各数据库的写法,这样就方便多了。

 

1.   sqltranslate函数用法

sql.sqltranslate(dbtype)

这个函数可以将SPL中简单SQL中的函数翻译成各种不同数据库的写法。这里的sql是需要翻译的SQL语句,dbtype是数据库类型。函数是指在SPL的简单SQL中定义过的函数,未定义的不会被翻译。已定义的函数列表和数据库类型请查阅sqltranslate函数帮助

编写一个SPL脚本文件sqltrans.dfx,设置两个参数sqldbtype


A

注释

1

=sql.sqltranslate(dbtype)

sql翻译成符合dbtype语法的SQL语句

2

=connect(dbtype)

连接数据库

3

=A2.query@x(A1)

用翻译后的A1在数据库查询出结果,关闭数据库连接

假设sql为下面的语句:

SELECT EID, NAME, BIRTHDAY, ADDDAYS(BIRTHDAY,10) DAY10 FROM EMP

运行这个脚本时传入参数dbtypeORACLE,运行后A1结果如下:

SELECT EID, NAME, BIRTHDAY, BIRTHDAY+NUMTODSINTERVAL(10,'DAY') DAY10 FROM EMP

如果传入参数dbtypeSQLSVR(SQL SERVER),运行后A1结果如下:

SELECT EID, NAME, BIRTHDAY, DATEADD(DD,10,BIRTHDAY) DAY10 FROM EMP

 

2.   Java中调用

SPL可以用JDBC方式被Java调用,调用sqltrans.dfx的代码如下:

Class.forName("com.esproc.jdbc.InternalDriver");
Connection con = DriverManager.getConnection("jdbc:esproc:local://");
PreparedStatement st = con.prepareCall("call sqltrans(?,?)");
st.setObject(1, "SELECT EID, NAME, BIRTHDAY, ADDDAYS(BIRTHDAY,10) DAY10 FROM EMP");
st.setObject(2, "ORACLE");
ResultSet rs = st.executeQuery();

这里的rs就是脚本文件中A3格返回的查询结果集。

更深入用法可参考Java如何调用SPL脚本》

 

如果只需要在Java程序中翻译SQL语句,可以直接调用api方法:

String sql = "SELECT NAME, BIRTHDAY, ADDDAYS(BIRTHDAY,10) DAY10 FROM EMP";
sql = com.raqsoft.dm.sql.SQLUtil.translate(sql, "ORACLE");

 

3.   新增数据库和函数定义

SPL中简单SQL的数据库类型和函数是在发布包esproc-bin-xxxx.jar中的字典文件/com/raqsoft/dm/sql/function.xml中定义的。文件部分内容如下图:

..

文件中FUNCTIONS节点代表一个函数组,type是函数组类型,FixParam表示是参数个数固定的函数组。

FUNCTION节点代表一个简单SQL函数,name是函数名,paramcount是参数个数,value是翻译本函数时的默认值,空串时表示无需翻译。

INFO节点代表一种数据库,dbtype是数据库名称,空串时表示是SPL中的简单SQLvalue是翻译到本数据库时的对应值。value中的??1代表函数的第1个参数值,?2代表函数的第2个参数值……依此类推。当INFO中的value值为空串时,则使用父节点FUNCTIONvalue值。

在翻译时,如果FUNCTION节点下没有指定数据库的INFO节点定义,则此函数保持原样,不被翻译。

如果要翻译的目标数据库在字典文件中没有定义,怎么办?可以修改字典文件来增加目标数据库,在需要翻译的函数节点FUNCTION下增加一个INFO节点。比如目标数据库名为MYDB,此数据库中对应函数ADDDAYS的语法为dayPlus(date,days),那么在字典中增加INFO节点如下:

..

修改字典后再运行sqltranslate("MYDB"),则前例中的SQL语句会被翻译成:

SELECT EID, NAME, BIRTHDAY, dayPlus(BIRTHDAY,10) DAY10 FROM EMP

 

如果需要增加一个新的函数,则在字典文件中新增写一个FUNCTION节点,再给它增加一些INFO子节点定义各种数据库中此函数应被翻译成什么语法即可。

 

 

以下是广告时间

对润乾产品感兴趣的小伙伴,一定要知道软件还能这样卖哟性价比还不过瘾? 欢迎加入好多乾计划。
这里可以低价购买软件产品,让已经亲民的价格更加便宜!
这里可以销售产品获取佣金,赚满钱包成为土豪不再是梦!
这里还可以推荐分享抢红包,每次都是好几块钱的巨款哟!
来吧,现在就加入,拿起手机扫码,开始乾包之旅



嗯,还不太了解好多乾?
猛戳这里
玩转好多乾