如何用 esProc 简化应用中的嵌套 SQL

 

数据分析或报表类应用中有时会遇到各类复杂的 SQL,嵌套了多层的、关联了自己的、动态转置的,比如:

From SQL to SPL:Create columns from distinct values of a column

From SQL to SPL: Statistics by time window

From SQL to SPL: Align the existing data to the corresponding position and fill in any missing data with 0

同样的任务,esProc SPL 的代码要比 SQL 简洁易懂。

下面,我们就来尝试一下如何将 esProc 集成到应用中,简化这些复杂 SQL。

先下载 esProc,推荐标准版:https://www.esproc.com/download-esproc/

下载并安装相应的版本。

安完 esProc 后,试一下 esProc IDE 是否可以正常访问数据库。先把数据库的 JDBC 放到目录 "[安装目录]\common\jdbc",这是 esProc 的类路径之一。比如 postgreSQL 的 JDBC:

Picture1png
打开 esProc IDE,找到菜单 "Tool->Connect to Data Source",新建 JDBC 数据源,填入具体数据库的连接信息,注意将来的代码中会用到数据源名。

Picture2png
返回到数据源界面并连接刚才配置的数据源,如果数据源名变成粉色,说明配置成功。

Picture3png
在 IDE 中新建脚本,写 SPL 语句,连接 postgreSQL 数据库,通过简单 SQL 加载第 1 个例子的数据:

=connect("pg16").query@x("select * from ventas")

按 ctrl-F9 执行,可以在 IDE 右边看到执行结果,以数据表的形式呈现,这对调试 SPL 代码很方便。

Picture4png
从数据库简单加载数据后,就可以用 SPL 简化复杂的 SQL 了。比如第 1 个例子的完整代码是:

=connect("pg16").query@x("select * from ventas where month>=? and month<=?",arg1,arg2).pivot@s(month;product,sum(amount))

先用参数过滤,再进行分组汇总后的转置,结果在右边:

Picture5png

第 1 个例子代码少,可以全写在一个单元格中,有些运算代码多,适合分步骤写在多个单元格,便于调试,比如第 2 个例子:Statistics by time window。

 A
1 =connect("pg16").query@x("select * from main where time>? and time<=?",arg1,arg2)
2 =A1.run(time=time@m(time))
3 =list=periods@s(A2.min(time),A2.max(time),60)
4 =A2.align@a(list,time)
5 =A4.new(list(#):start, elapse@s(start,60):end, sv=ifn(end_value[-1],~.value):start_value, ifn(~.m(-1).value, sv):end_value, ifn(~.min(value),sv):min, ifn(~.max(value),sv):max)

把上面脚本保存在某个目录中,比如 D:\data\mainProc.splx,运行后可以看到结果:

Picture6png

在 IDE 中调试通过后,下面配置 Java 应用环境。
从目录 "[安装目录]\esProc\lib" 下找到 esProc JDBC 相关的 jar 包:esproc-bin-xxxx.jar、icu4j_60.3.jar。

Picture7png
将这两个 jar 包部署到 Java 开发环境的类路径下。
再从目录 "[安装目录]\esProc\config" 下找到 esProc 配置文件 raqsoftConfig.xml,同样部署到 Java 开发环境的类路径下。

Picture8png
配置文件中要改的配置项是 mainPath,这表示脚本等文件的默认路径。注意数据源的信息也在配置文件中。
接下来,就可以编写 Java 代码,通过 esProc JDBC 执行 SPL 了,先试试例子 2:

Class.forName("com.esproc.jdbc.InternalDriver");
Connection con= DriverManager.getConnection("jdbc:esproc:local://");
PreparedStatement st = con.prepareCall("call mainProc(?,?)");
st.setTime(1,Time.valueOf("10:00:00"));
st.setTime(2,Time.valueOf("11:00:00"));
ResultSet rs = st.executeQuery();

运行后可以看到结果:

Picture9png
可以看到,esProc JDBC 调用 SPL 脚本过程和数据库 JDBC 调用存储过程一样。
例子 1 的代码比较少,可以直接把 SPL 代码嵌入 Java,不用脚本文件保存代码。

PreparedStatement st = con.prepareStatement("=connect(\"pg16\").query@x(\"select * from ventas where month>=? and month<=?\",?,?).pivot@s(month;product,sum(amount))");
st.setInt(1,2);
st.setInt(2,4);
ResultSet rs = st.executeQuery();

执行后可以看到计算结果:

Picture10png

可以看到,SPL 嵌入 Java 的过程和 SQL 嵌入 Java 一样。
SPL 脚本可以转为 SPL 代码,比如例子 2,先在 IDE 中打开脚本文件,选中有代码的单元格 A1-A5,再点击菜单 "Edit->Copy->Code copy",这样就把多行多列的网格代码转成了单行的 SPL 代码,暂存在粘贴板里。

Picture11png
将转换后的 SPL 代码复制到 Java 代码中,将参数名替换成问号并执行,结果在下面:

Picture12png
esProc 官网上还有很多简化 SQL 的例子,数据库程序员不容错过。