Java 搞定 SQL 集合运算的最简方法

问题介绍

  作为 java 程序员,用代码直接实现类似 SQL 中的交并补差的集合运算,总是要编写大量的代码,如果能有一个专门的外部数据工具,通过写简单类似 SQL 的脚本来实现,在 java 中直接调用并可以返回结果集,就再好不过了。Java 版集算器正是解决这一难题的神器,通过 SPL 脚本可以直观自然得写出运算,再使用 java 调用 SPL 脚本,使用起来简单,快捷,高效。另外,虽然 SQL 有集合概念,但对于有序集合运算提供的支持却很有限,经常要采用很费解的思路才可以完成, SPL 基于离散数据集模型,能轻松处理有序集合运算。下面我们就由浅入深,举例说明如何使用。

SPL 实现

和集

示例 1: 求重叠时间段的总天数

MySQL8:

with recursive t(start,end) as (select date'2010-01-07',date'2010-01-9'union all select date'2010-01-15',date'2010-01-16'union all select date'2010-01-07',date'2010-01-12'union all select date'2010-01-08',date'2010-01-11'),

t1(d,

end) as (select start,end fromt

union all selectd+1,end from t1 whered

select count(distinctd)from t1;

  说明:此例先将各时间段转成时间段内所有日子对应的日期,然后再求不同日期的个数

集算器 SPL:


A3: 对 A2 中的每一个时间段构造从 start 到 end 的日期序列

A4: 求 A3 中所有日期序列的和

A5: 求 A4 中不重复日期的个数

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

差集

示例 1: 列出英语人口和法语人口均超过 5% 的国家

MySQL8:

with t1(lang) as (select 'English' union all select 'French')

select name fromworld.countryc

where not exists(select * from t1 where lang not in (select language fromworld.countrylanguage

where percentage>=5 andcountrycode=c.code

)

);

  说明:此 SQL 只是演示通过双重否定实现差集为空

集算器 SPL:


A4: 选出 [“English”,”French”] 与本组语言集合的差为空的组,意思就是选出语言集合包含 English 和 French 的组

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

交集

示例 1: 列出英语人口、法语人口、西班牙语人口分别超过 0.3%、0.2%、0.1% 的国家代码

MySQL8:

with t1 as (select countrycode from world.countrylanguage where language='English' and percentage>0.3),

t2

as (select countrycode from world.countrylanguage where language='French' and percentage>0.2),

t3

as (select countrycode from world.countrylanguage where language='Spanish' and percentage>0.1)

selectcountrycode

from t1 join t2 using(countrycode) join t3 using(countrycode);

  说明:此例只是演示如何求解多个集合的交集

集算器 SPL:


A3: 按次序依次查询英语人口超 0.3%、法语人口超 0.2%、西班牙语超 0.1% 的国家代码,并转成序列

A5: A3 中所有序列交集

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

Java 调用

SPL 嵌入到 Java 应用程序十分方便,通过 JDBC 调用存储过程方式加载,用和集保存的文件SumSet.dfx,示例调用如下:

...

Connection con =null;

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

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

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

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

//执行存储过程

st.execute();

//获取结果集

ResultSet rs = st.getResultSet();

...

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

扩展节选

  关于集合运算除了上面讲的和差交运算,还可以获取与行号有关的计算,以及有序集合的对位运算。

根据行号取数据

示例 1: 计算招商银行 (600036) 2017 年第 3 个交易日和倒数第 3 个交易日的交易信息

MySQL8:

with t as (select *, row_number() over(order by tdate) rn from stktrade where sid='600036' and tdate between '2017-01-01' and '2017-12-31')

select tdate,open,close,volume fromtwhere rn=3unionall

select tdate,open,close,volume fromtwhere rn=(select max(rn)-2 fromt);

集算器 SPL:


A3: 第 3 条记录和倒数第 3 条记录的和集

示例 2: 计算招商银行 (600036) 最近 20 个交易日的平均收盘价

MySQL8:

with t as (select *, row_number() over(order by tdate desc) rn from stktrade where sid='600036')

select avg(close) avg20 fromtwhere rn<=20;

集算器 SPL:


A2: 将 600036 的交易记录按日期排序

A3: 取从倒数 20 条到末尾的所有记录

A4: 求 A3 中所有记录收盘价的平均值

求满足条件的记录的行号

示例 1: 计算招商银行 (600036)2017 年经过多少交易日收盘价达到 25 元

MySQL8:

with t as (select *, row_number() over(order by tdate) rn from stktrade where sid='600036' and tdate between '2017-01-01' and '2017-12-31')

select min(rn) fromtwhere close>=25;

集算器 SPL:


A3: 从前往后查找第 1 个收盘价达到 25 元的记录位置

示例 2: 计算格力电器 (000651) 2017 年涨幅 (考虑停牌)

MySQL8:

with t as (select * from stktrade where sid='000651'),

t1(d)

as (select max(tdate) fromtwhere tdate<'2017-01-01'),

t2(d)

as (select max(tdate) fromtwhere tdate<'2018-01-01')

selects2.close/s1.close-1rise

from (select * fromt,t1wheretdate=d) s1,

(

select * fromt,t2wheretdate=d) s2;

集算器 SPL:


A2: 数据按交易日从小到大排序

A3: 从后往前查找交易日在 2017-01-01 之前的最后一条记录在序列中的行号

A4: 求 2016 年收盘价

A5: 求 2017 年收盘价,其中 A2.m(-1) 取倒数第 1 条记录,即 2017 年最后一个交易日对应的记录

示例 3: 列出 2017 年信息发展 (300469) 交易量超过 250 万股时的交易信息及各日涨幅(考虑停牌)

MySQL8:

with t as (select *, row_number() over(order bytdate) rn

from stktrade where sid='300469' and tdate<=date '2017-12-31'),

t1

as (select * fromtwhere tdate>=date'2017-01-01' and volume>=2500000)

selectt1.tdate, t1.close,t.volume, t1.close/t.close-1rise

from t1 jointont1.rn=t.rn+1;

集算器 SPL:


A3: 求出 2017 年交易量超 250 万股所有记录的行号

A4: 根据行号计算相应的日期、收盘价、交易量、涨幅

求最大值或最小值所在记录的行号

示例 1: 计算招商银行 (600036) 2017 年最早的最低价与最早的最高价间隔多少交易日

MySQL8:

with t as (select *, row_number() over(order by tdate) rn from stktrade where sid='600036' and tdate between '2017-01-01' and '2017-12-31'),

t1

as (select * fromtwhere close=(select min(close) fromt)),

t2

as (select * fromtwhere close=(select max(close) fromt))

select abs(cast(min(t1.rn) as signed)-cast(min(t2.rn) assigned)) inteval

from t1,t2;

集算器 SPL:


A3: 从前往后找最大收盘价在序列中的行号

A4: 从前往后找最小收盘价在序列中的行号

示例 2: 计算招商银行 (600036) 2017 年最后的最低价与最后的最高价间隔多少交易日

MySQL8:

with t as (select *, row_number() over(order by tdate) rn from stktrade where sid='600036' and tdate between '2017-01-01' and '2017-12-31'),

t1

as (select * fromtwhere close=(select min(close) fromt)),

t2

as (select * fromtwhere close=(select max(close) fromt))

select abs(cast(max(t1.rn) as signed)-cast(max(t2.rn) assigned)) inteval

from t1,t2;

集算器 SPL:


A3: 从后往前找最大收盘价在序列中的行号

A4: 从后往前找最小收盘价在序列中的行号

有序集合间的对位计算

示例 1: 求 2018 年 3 月 6 日到 8 日创业板指 (399006) 对深证成指 (399001) 的每日相对收益率

MySQL8:

with t1 as (select *,close/lag(close) over(order by tdate) rise from stktrade where sid='399006' and tdate between '2018-03-05' and '2018-03-08'),

t2

as (select *, close/lag(close) over(order by tdate) rise from stktrade where sid='399001' and tdate between '2018-03-05' and '2018-03-08')

selectt1.rise-t2.rise

from t1 join t2 using(tdate)

where t1.rise is not null;

集算器 SPL:


A2: 依次查询 399006 和 399001 从 2018 年 3 月 5 日到 8 日的交易数据

A4: 依次计算 A2 中 2 个序表从第 2 条记录到第 4 条记录的涨幅,也就是 399006 和 399001 从 2018 年 3 月 6 日到 8 日的每天涨幅

A5: 对位相减,即可算出每日相对收益率

SPL 优势

有库写 SQL,没库写 SPL

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

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

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

技术文档和社区支持

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容

  • 【摘要】 SQL 虽然有集合概念,但对于集合运算、特别是有序集合运算,提供的支持却很有限,经常要采用很费解的思路才...
    小黄鸭呀阅读 395评论 0 0
  • ORACLE自学教程 --create tabletestone ( id number, --序号usernam...
    落叶寂聊阅读 1,077评论 0 0
  • 50个常用的sql语句Student(S#,Sname,Sage,Ssex) 学生表Course(C#,Cname...
    哈哈海阅读 1,231评论 0 7
  • 忘记了上次见面是多久之前,一起吃的香辣蟹,没有吃多少就结束了,说要开车送我。 我自己走了,是不是人就是这样,越是想...
    蓓蓓摸摸头阅读 299评论 0 0
  • 归心 轻雾薄霜,未见霞光,两个鸭子玩耍,只见冰水一汪。春风抱着清寒,游子怀着思乡。 炊烟盈盈,是剪不断的乡愁,狗吠...
    相辞江湖远阅读 155评论 0 0