问题介绍

要在 Java 代码中实现类似 SQL 中的 GroupBy 分组聚合运算,是比较繁琐的,通常先要声明数据结构(Java 实体类),然后用 Java 集合进行循环遍历,最后根据分组条件添加到某个子集合中。Java 8 有了 Lambda(stream)代码简洁了许多,分组后往往还要跟着聚合操作,仍然需要单写聚合函数 sum(),count(*),topN()等。这些还都是最常规的分组和聚合运算,遇到对位分组、枚举分组、多重分组等非常规分组加上其他聚集函数 (FIRST,LAST…),代码就变得非常冗长且不通用。如果能有一个中间件专门负责这类计算,采用类似 SQL 脚本做算法描述,在 Java 中直接调用脚本并返回结果集就好了。Java 版集算器和 SPL 脚本,就是这样的机制,下面举例说明如何使用。

SPL 实现

常规分组

duty.xlsx 文件中保存着每个人的加班记录:

汇总每个人的值班天数:

保存脚本文件CountName.dfx(嵌入 Java 会用到)

每组 TopN

取每个月、每个人、头三天的加班记录

保存脚本文件RecMonTop3.dfx(嵌入 Java 会用到)

Java 调用

SPL 嵌入到 Java 应用程序十分方便,通过 JDBC 调用存储过程方法加载,用常规分组保存的文件CountName.dfx,示例调用如下:

...

Connection con = null;

Class.forName("com.esproc.jdbc.InternalDriver");

con= DriverManager.getConnection("jdbc:esproc:local://");

//调用存储过程,其中CountName是dfx的文件名

st =(com. esproc.jdbc.InternalCStatement)con.prepareCall("call CountName()");

//执行存储过程

st.execute();

//获取结果集

ResultSet rs = st.getResultSet();

...

...

Connection con = null;

Class.forName("com.esproc.jdbc.InternalDriver");

con= DriverManager.getConnection("jdbc:esproc:local://");

//调用存储过程,其中CountName是dfx的文件名

st =(com. esproc.jdbc.InternalCStatement)con.prepareCall("call CountName()");

//执行存储过程

st.execute();

//获取结果集

ResultSet rs = st.getResultSet();

...

替换成 RecMonTop3.dfx 是同样的道理,只需 call RecMonTop3() 即可,也可同时返回两个结果集。这里只用 Java 片段粗略解释了如何嵌入 SPL,详细步骤请参阅 Java 如何调用 SPL 脚本 ,也非常简单,不再赘述。同时,SPL 也支持 ODBC 驱动,集成到支持 ODBC 的语言,嵌入过程类似。

拓展节选

之前没有相关的总结,其实关于数据分组,细分起来其实还有很多种,对位分组、枚举分组、多重分组…,在乾学院 SPL 官方论坛都有总结和示例,这里节选其中两种。

SPL 对位分组

示例 1:按顺序分别列出使用 Chinese、English、French 作为官方语言的国家数量

MySQL8:

with t(name,ord) as (select 'Chinese',1

union all select 'English',2

union all select 'French',3)

select t.name, count(countrycode) cnt

from t left join world.countrylanguage s on t.name=s.language

where s.isofficial='T'

group by name,ord

order by ord;

MySQL8:

with t(name,ord) as (select 'Chinese',1

union all select 'English',2

union all select 'French',3)

select t.name, count(countrycode) cnt

from t left join world.countrylanguage s on t.name=s.language

where s.isofficial='T'

group by name,ord

order by ord;

注意:表的字符集和数据库会话的字符集要保持一致。

(1) show variables like ’character_set_connection’查看当前会话字符集

(2) show create table world.countrylanguage 查看表的字符集

(3) set character_set_connection=[字符集] 更新当前会话字符集

集算器 SPL:

A1: 连接数据库

A2: 查询出所有官方语言的记录

A3: 需要列出的语言

A4: 将所有记录按 Language 对位到 A3 相应位置

A5: 构造以语言和使用此语言为官方语言的国家数量的序表

示例 2:按顺序分别列出使用 Chinese、English、French 及其它语言作为官方语言的国家数量

MySQL8:

with t(name,ord) as (select 'Chinese',1 union all select 'English',2

union all select 'French',3 union all select 'Other', 4),

s(name, cnt) as (

select language, count(countrycode) cnt

from world.countrylanguage s

where s.isofficial='T' and language in ('Chinese','English','French')

group by language

union all

select 'Other', count(distinct countrycode) cnt

from world.countrylanguage s

where isofficial='T' and language not in ('Chinese','English','French')

)

select t.name, s.cnt

from t left join s using (name)

order by t.ord;

MySQL8:

with t(name,ord) as (select 'Chinese',1 union all select 'English',2

union all select 'French',3 union all select 'Other', 4),

s(name, cnt) as (

select language, count(countrycode) cnt

from world.countrylanguage s

where s.isofficial='T' and language in ('Chinese','English','French')

group by language

union all

select 'Other', count(distinct countrycode) cnt

from world.countrylanguage s

where isofficial='T' and language not in ('Chinese','English','French')

)

select t.name, s.cnt

from t left join s using (name)

order by t.ord;

集算器 SPL:

A4: 将所有记录按 Language 对位到 A3.to(3) 相应位置,并追加一组用于存放不能对位的记录

A5: 第 4 组计算不同 CountryCode 的数量

SPL 枚举分组

示例 1:按顺序列出各类型城市的数量

MySQL8:

with t as (select * from world.city where CountryCode='CHN'),

segment(class,start,end) as (select 'tiny', 0, 200000

union all select 'small', 200000, 1000000

union all select 'medium', 1000000, 2000000

union all select 'big', 2000000, 100000000

)

select class, count(1) cnt

from segment s join t on t.population>=s.start and t.population

group by class, start

order by start;

MySQL8:

with t as (select * from world.city where CountryCode='CHN'),

segment(class,start,end) as (select 'tiny', 0, 200000

union all select 'small', 200000, 1000000

union all select 'medium', 1000000, 2000000

union all select 'big', 2000000, 100000000

)

select class, count(1) cnt

from segment s join t on t.population>=s.start and t.population

group by class, start

order by start;

集算器 SPL:

A3: ${…} 宏替换,以大括号内表达式的结果作为新表达式进行计算,结果为序列 [“?<200000”,“?<1000000”,“?<2000000”,“?<100000000”]

A5: 针对 A2 中每条记录,寻找 A3 中第 1 个成立的条件,并追加到对应的组中

示例 2:列出华东地区大型城市数量、其它地区大型城市数量、非大型城市数量

MySQL8:

with t as (select * from world.city where CountryCode='CHN')

select 'East&Big' class, count(*) cnt

from t

where population>=2000000

and district in ('Shanghai','Jiangshu', 'Shandong','Zhejiang','Anhui','Jiangxi')

union all

select 'Other&Big', count(*)

from t

where population>=2000000

and district not in ('Shanghai','Jiangshu','Shandong','Zhejiang','Anhui','Jiangxi')

union all

select 'Not Big', count(*)

from t

where population<2000000;

MySQL8:

with t as (select * from world.city where CountryCode='CHN')

select 'East&Big' class, count(*) cnt

from t

where population>=2000000

and district in ('Shanghai','Jiangshu', 'Shandong','Zhejiang','Anhui','Jiangxi')

union all

select 'Other&Big', count(*)

from t

where population>=2000000

and district not in ('Shanghai','Jiangshu','Shandong','Zhejiang','Anhui','Jiangxi')

union all

select 'Not Big', count(*)

from t

where population<2000000;

集算器 SPL:

A5: enum@n 将不满足 A4 中所有条件的记录存放到追加的最后一组中

示例 3:列出所有地区大型城市数量、华东地区大型城市数量、非大型城市数量

MySQL8:

with t as (select * from world.city where CountryCode='CHN')

select 'Big' class, count(*) cnt

from t

where population>=2000000

union all

select 'East&Big' class, count(*) cnt

from t

where population>=2000000

and district in ('Shanghai','Jiangshu','Shandong','Zhejiang','Anhui','Jiangxi')

union all

select 'Not Big' class, count(*) cnt

from t

where population<2000000;

MySQL8:

with t as (select * from world.city where CountryCode='CHN')

select 'Big' class, count(*) cnt

from t

where population>=2000000

union all

select 'East&Big' class, count(*) cnt

from t

where population>=2000000

and district in ('Shanghai','Jiangshu','Shandong','Zhejiang','Anhui','Jiangxi')

union all

select 'Not Big' class, count(*) cnt

from t

where population<2000000;

集算器 SPL:

A6: 若 A2 中记录满足 A4 中多个条件时,enum@r 会将其追加到对应的每个组中

优势总结

有库写 SQL,没库写 SPL

用 Java 程序直接汇总计算数据,还是比较累的,代码很长,并且不可复用,很多情况数据也不在数据库里,有了 SPL,就能像在 Java 中用 SQL 一样了,十分方便。

常用无忧,不花钱就能取得终身使用权的入门版

如果要分析的数据是一次性或临时性的,润乾集算器每个月都提供免费试用授权,可以循环免费使用。但要和 Java 应用程序集成起来部署到服务器上长期使用,定期更换试用授权还是比较麻烦,润乾提供了有终身使用权的入门版,解决了这个后顾之忧,获得方式参考 如何免费使用润乾集算器?

技术文档和社区支持

官方提供的集算器技术文档本身就有很多现成的例子,常规问题从文档里都能找到解决方法。如果获得了入门版,不仅能够使用 SPL 的常规功能,碰到任何问题都可以去乾学院上去咨询,官方通过该社区对入门版用户提供免费的技术支持。

java spl 是什么_Java 嵌入 SPL 轻松实现数据分组相关推荐

  1. excel函数去重_Java 嵌入 SPL 轻松实现 Excel 文件合并

    大多数JAVA程序猿都选择使用POI或者HSSFWorkbook等第三方类库来实现Excel自动化合并,这样一来不仅需要噼里啪啦的敲好多代码,费事费力,而且用起来灵活度也不高,对Excel的格式要求也 ...

  2. Java 嵌入 SPL 轻松实现数据分组

    要在 Java 代码中实现类似 SQL 中的 GroupBy 分组聚合运算,是比较繁琐的,通常先要声明数据结构(Java 实体类),然后用 Java 集合进行循环遍历,最后根据分组条件添加到某个子集合 ...

  3. java excel 展开折叠_Java在Excel中创建多级分组、折叠或展开分组的实现

    本文介绍通过java程序在excel创建分组的方法,可对行或列分组进行分组并设置明细数据是否展开或折叠.设置数据分组并展开或折叠时,可通过以下方法: 方法一: 通过方法sheet.groupbyrow ...

  4. java json解析 代码_Java构造和解析Json数据的两种方法详解一

    在www.json.org上公布了很多JAVA下的json构造和解析工具,其中org.json和json-lib比较简单,两者使用上差不多但还是有些区别.下面首先介绍用json-lib构造和解析Jso ...

  5. java中参数存储_Java中函数参数传递和数据存储

    值传递是将要传递的值作为一副本传递的.. 引用传递,传递的是引用对象的内存地址.. 例如: int i=4; int j=i;   //相当于把4复制了一个副本赋给了j 输出结果是i=4 ,j=4 C ...

  6. java拆分单元格_Java 拆分Excel单元格数据为多列

    一.概述及使用工具 在Excel表格里面,可设置将单元格中的文本数据按分隔符拆分为多列,下面通过Java程序来介绍具体实现方法.这里使用Free Spire.XLS for Java(免费版)来实现数 ...

  7. java 正则高级应用_JAVA正则表白式高级用法(分组与捉拿).

    ((A)(B(C)))/A(B(C))(C) 组零始终代表全副表白式 之因而这么命名捉拿组是因为在相称中,保留了与这些组相称的输入序列的每个子序列.捉拿的子序列稍后能够穿越 Back 引用在表白式中利 ...

  8. java mysql sql注入_Java防SQL注入MySQL数据查询

    /** * */ package user.DAO; import java.sql.*; import user.entity.User; /** *//** * 用户数据访问层 * @author ...

  9. java 返回 json格式_java 如何返回json格式数据,需要技巧

    今天上午给同事调了半个小时的程序,最后发现是在后台代码的java返回json格式的数据出了个错误.因此就想到了广大的初学者一开始学习jquery的时候可能会遇到这个问题.现在我就把我的给大家分享一下, ...

最新文章

  1. HttpClient 如何设置请求接口等待时间
  2. mysql事务拼写_拼写mysql单词
  3. ^和$ emeditor
  4. python3 数组大小_python3从零学习-5.1.8、高效的数值数组array
  5. 茫茫内存,我该如何用 windbg 找到你 ?
  6. java.sql 拒绝连接_hive jdbc 拒绝连接问题
  7. 资源丨MySQL故障排查思路方法PPT视频24问答
  8. 【JMX】JMX 远程 连接 The client has been closed
  9. 中国团队屠榜:COCOMapillary挑战赛包揽全部冠军
  10. 8086可以用c语言编程吗,[求助]如何将C程序反汇编成8086汇编程序
  11. pxe dhcp offer之后没有_秒懂DHCP是什么
  12. linux目录与文件,Linux目录与文件基本操作
  13. 平面直角坐标系中的旋转公式_难点解析丨空间直线、平面平行的判定及其性质...
  14. 传统企业如何精准获客?搭上这趟高科技顺风车
  15. 关于投资有哪些不得不读的书籍?
  16. 永远不怕IE主页地址被修改
  17. java期未项目_Java项目实战知到期末答案
  18. 微信开发修改button里的字体大小_在微信小程序中如何修改文字大小
  19. CMS简数采集数据发布到迅睿CMS教程
  20. 自动驾驶(七)---------初探轨迹规划

热门文章

  1. [转载]Android wifi探究一:初步认识wpa_supplicant与wifi框架梳理
  2. PullToRefresh使用详解(一)--构建下拉刷新的listView
  3. 有品css进度12.6
  4. Python 二分查找与方程求解(公开代码)
  5. x86汇编 linux,Linux操作系统的X86汇编程序设计
  6. html5怎么让图片在导航栏后,请问前端大神,html如何引入另一个html,写了一个导航栏想在多个页面中如何重复使用?...
  7. EEPROM读写实验
  8. 为什么hashcode的算法要用31作为乘子
  9. QT自制TCP客户端
  10. STM32通过串口进入和唤醒停止模式