怎么轻松实现报表跨库移植

有些应用系统中的报表需要基于多种不同数据库工作,这就带来了移植的工作。报表的取数 SQL 中可能大量用到数据库的计算函数,而不同数据库语法差异很大。报表想要在不同数据库上运行,经常要手工改这些 SQL,费时费力。
完全自动改造 SQL 是不现实的,因为数据库功能的差异使得某些复杂计算很难直接迁移。不过,梳理一下会发现,大部分不兼容问题都是由于 SQL 函数写法不同造成的。特别是日期和字符串相关的函数,不同数据库的写法完全不同。换库每次都得改一遍,还要维护多个版本,非常麻烦。
比如将字符串 “2020-02-05” 转换成日期,不同数据库有不同的写法。

#ORACLE:
select TO_DATE('2020-02-05', 'YYYY-MM-DD') from USER
#SQL Server:
select CONVERT(varchar(100), '2020-02-05', 23) from USER
#MySQL:
select DATE_FORMAT('2020-02-05','%Y-%m-%d') from USER

润乾报表集成了可以转换 SQL 方言的 SPL 引擎,能轻松搞定这个问题,换库也不用改报表,能做到完全透明化移植。

比如订单查询报表,其中 SQL 中使用了 adddays 函数:

SELECT order_id,user_id,order_date,adddays(order_date,10) as day10,total_amount FROM orders where order_date>=? and order_date<=?

这个 adddays 函数不同数据库的写法是不一样的:
Oracle 是:

order_date+NUMTODSINTERVAL(10,'DAY')

MySQL 是:

order_date+INTERVAL 10 DAY

PostgreSQL 是:

order_date+interval '10 days'

MSSQL 又是这样:

DATEADD(DD,10,order_date)

如果数据库配置的是 MySQL,怎么能转化成 MySQL 的语法呢?

需要先为报表配置一个 SPL 数据源,标准 JDBC 方式:

注意,连接 URL 中有这样一串参数:jobVars=dbType:MYSQL,dbName:mysqlds,dbType 代表数据库类型,dbName 则代表数据源名称。这两个参数是做什么的呢?先往后看。

接着需要将报表模板的数据源指定成前面配置的数据源 esproc:

这么配置完,报表运行时就会将 SQL 发给 SPL。然后就是要完成翻译的工作了。

SPL 提供了 JDBC 网关功能,所有通过 JDBC 发送的 SQL 都会交给网关处理,我们自然可以在网关中完成翻译和数据查询。

把 SPL 的核心配置文件 raqsoftConfig.xml 放在应用类目录后配置一下网关:

<JDBC>
<load>Runtime,Server</load>
	<gateway>gateway.splx</gateway>
</JDBC>

这里指定了一个 SPL 脚本(gateway.splx),下面是脚本内容:


A

B

1

=sql=trim(sql).sqltranslate(dbType)


2

=argsN=args.len()

=("sql"|argsN.("args("/~/")")).concat@c()

3

=connect(dbName)

return A3.query@x(${B2})

这是一个通用脚本,可以处理任意 SQL。脚本有两个参数,sql 用于接收报表传递的 SQL 语句,args 接收 SQL 中的参数:

而脚本还用到了 dbType 和 dbName,这就是 JDBC 中 url 传递过来的两个参数。SPL 的 SQL 翻译函数 sqltranslate 需要类型参数,最后执行 SQL 查询数据也需要数据源信息(dbName)。
这个数据源连接是在 SPL 配置文件 raqsoftConfig.xml 中设置的:

<DB name="mysqlds">
<property name="url" value="jdbc:mysql://127.0.0.1:3306/raqdb?useSSL=false&amp;useCursorFetch=true"/>
<property name="driver" value="com.mysql.jdbc.Driver"/>
…
</DB>

也就是 MySQL 的数据库连接,更换数据库需要重新配置数据源,并将报表中的 esproc 数据源 URL 也对应修改即可。

完成上面的步骤,再查询报表就可以正常展现:

监控后台的 SQL 也可以发现原来的:

SELECT order_id,user_id,order_date,adddays(order_date,10) as day10,total_amount FROM orders where order_date>=? and order_date<=?

已经被翻译成 MySQL 对应的语法:

SELECT order_id,user_id,order_date,order_date+INTERVAL 10 DAY as day10,total_amount FROM orders where order_date>=? and order_date<=?

如果要换数据库只要改 SPL JDBC 中的 URL 参数和数据库数据源配置。比如要换成 PG,URL 改成这样:

url=”jdbc:esproc:local://?jobVars=dbType: POSTGRES,dbName:pgds”

对应的数据源改成:

<DB name="pgds">
<property name="url" value="jdbc:postgresql://192.168.0.1:5432/mypg"/>
<property name="driver" value="org.postgresql.Driver"/>
…
</DB>

润乾报表现在已经内置了大量函数供使用,包括数十个常用的字符串函数、时间函数等,碰到未支持的还可以通过配置 XML 文件进行扩展,覆盖面没得说。

顺便说一句,拥有如此强大移植能力的润乾报表,因为采用低成本的互联网营销模式,售价也非常便宜:一万一套,三万买断,可以说是最具性价比的报表工具了。