千家信息网

浅解比 SQL 更好用的 SPL(二)

发表于:2026-10-31 作者:千家信息网编辑
千家信息网最后更新 2026年10月31日,从 SQL 到SPL基本查询语法迁移 之多表操作上一篇我们针对单表的情形了解了如何把数据计算从 SQL 查询迁移到集算器,或者更准确地说,迁移到集算器所使用的SPL集算语言。这个迁移过程,既有相同的概
千家信息网最后更新 2026年10月31日浅解比 SQL 更好用的 SPL(二)

从 SQL 到SPL基本查询语法迁移 之多表操作

上一篇我们针对单表的情形了解了如何把数据计算从 SQL 查询迁移到集算器,或者更准确地说,迁移到集算器所使用的SPL集算语言。这个迁移过程,既有相同的概念,也有不同的思路。

接下来,我们一起针对多表的情况看一下集算器和SPL语言是如何发挥更大的优势的。

JOIN 连接两个记录

在前面的例子中,我们得到了每个雇员的销售额,如果进一步还想知道每个雇员给出的最小折扣,那就又复杂了些。因为折扣信息在另一张订单明细表里。急性子的朋友可能上来就要 JOIN 两个表,然后再聚合两个测度字段--这样就算错了!正确的做法应该是每个测度字段先按分组聚合出结果,之后再 JOIN。这是因为先 JOIN 的话可能导致结果中出现重复记录。

按照这个思路写出 SQL,并和集算器中的SPL代码进行比较:

SQL

select t1.employeeId, salesAmount, lowestDiscount from (
select employeeId, sum(money) salesAmount from order
where orderDate>='2012-01-01′ and orderDate<'2012-02-01'
group by employeeId
having sum(money)>5000) t1
left join (
select employeeId, min(discount) lowestDiscount from order
join orderDetail on order.orderId=orderDetail.orderId
where orderDate>='2012-01-01′ and orderDate<'2012-02-01'
group by employeeId) t2
on t1.employeeId=t2.employeeId

集算器A
1=connect("hsqlDB")
2=A1.query("select * from order")
3=A2.select(orderDate>=date("2012-01-01") && orderDate
4=A3.group(employeeId;~.sum(money):salesAmount)
5=A4.select(salesAmount>5000)
6=A1.query("select * from orderDetail")
7=join(A3:order,orderId;A6:orderDetail,orderId)
8=A7.group(A7.order.employeeId:employeeId;~.min(orderDetail.discount):lowestDiscount)
9=join(A5:r1,employeeId;A8:r2,employeeId)
10=A9.new(r1.employeeId:employeeId,r1.salesAmount:salesAmount,r2.lowestDiscount:lowestDiscount)
11>A1.close()

A5 之前是我们做过的聚合符合条件的按雇员分组的销售额;
A6 查出订单明细表的所有数据;

A7 中的SPL用到了对应 SQL 的多表连接的新函数 join。join 函数把两个表连接起来,这里它的参数的含义是:将 A3 序表起一个别名 order,A6 序表起一个别名 orderDetail,然后用两个表各自的 orderId 作为关联字段,观察 A7 的结果如下:

可以看到,join 后形成的序表有 order、orderDetail 两个字段,两个字段的值分别直接指向了两个原始序表的记录,这就是说字段的值可以是复杂数据类型(包括序表、序列类型),也可以嵌套多层结构的数据,这是 SQL 语法里不允许的,也是SPL的特色和优势之一。

下图比较形象地说明了这种结构(长方形表示序表、椭圆形表示记录、三角形表示关联字段):

A8 直接用SPL中的 group 函数对这个复杂结构的序表进行分组聚合运算,获得各个雇员曾经给出的最小折扣。

再需要注意的一点是 A3 序表被后面两个不同的动作(A4、A7)都使用了一次,达到了中间结果复用的效果。这种方式对于越是复杂的计算,往往作用越大,可以起到类似"数据模块化"的作用。

在 A9 中通过SPL的 join 函数把 A5(销售额超过 5000)、A8(最小折扣)两个序表连接起来;

最后,A10 使用 new 函数生成新的序表结构,而数据来自 A9 复杂结构记录的不同层次位置。

A10 最终的结果如下:

简单回顾一下,对于最后这个比较复杂的 SQL,如果你是个 SQL 高手,可能会看出第二个子查询里的 where 并不是必须的,之所以保留它,是因为有可能会缩小处理数据的范围,从而提升一些性能。这也是 SQL 的另一个特点,一方面需要不喘气的一句话把整个查询表达出来,另一方面还需要同时考虑性能优化因素,甚至即便考虑到了优化方案,也不一定能轻松、自然地描述出来。

在上面的例子中,不难体会出集算器以及SPL对分步过程的重视,每一个步骤的结果都是可以随时观察的,而且前面步骤的结果也可以重复利用,同时执行步骤也可以被程序员自由定制。这些特点最直接的好处是降低了学习和编码的难度,而更本质的是符合人的自然思维,为描述复杂计算奠定了基础。

UNION 等合并两个集合

SQL 中还有一类针对多个集合(表)的运算,就是常说的并、合、交、差(UNION、UNION ALL、INTERSECTION、MINUS),与之对应的,在SPL中表示为 &、|、^、\。

集合运算时常需要判断一条记录是否重复,在这个细节上,SQL 和SPL有一点区别。SPL里因为序表、记录,以及字段的值都被看成是一个对象,所以在进行并集运算时,可以比对元素是否为同一个对象,而 SQL 的记录是抽象的,不是一个实体对象,所以只能通过逐个比对两条记录的字段值来判断是否重复。

我们来看一下实际的例子:

集算器AB
1=connect("hsqlDB")

2=A1.query("select * from order")

3=A2.select(orderId>10251 && orderId<10256)=A2.select(orderId>10254 && orderId<10258)
4=A3&B3=A3B3
5=A3^B3=A3\B3
6>A1.close()

A3 序表的结果:

B3 序表的结果:

A3&B3,去掉重复合并到一起,并集运算后得到 A4 序表的结果:

A3|B3,保留重复合并到一起,合集运算后得到 B4 序表的结果:

A3^B3,取 A3 和 B3 里相同的记录,交集运算后得到 A5 序表的结果:

A3\B3,A3 里去掉 B3 中存在的记录,差集运算后得到 A5 序表的结果:

其它常用语法

最后,再看两个常用的 SQL 函数语法,我们来对比看一下SPL的实现。

CASE WHEN …

SQL 中的 case when … then … else … end,在SPL中用 if 函数,语法是if(条件, 真值, 假值),下面的例子是把 employeeId<5 的分为一组,剩余的分到另一组:

SQL
select (case when employeeId<5 then 1 else 2 end) groupId, orderId from order
集算器A
1=connect("hsqlDB")
2=A1.query("select * from order")
3=A2.new(if(employeeId<5,1,2):groupId,orderId)
4>A1.close()

COALESCE(exp1,exp2…expn)

SPL中仍然用 if 函数,if(条件, 真值, 假值),下面这个例子把 1000 这个特殊的值赋值给为 null 的 employeeId。

SQL
select coalesce(employeeId,1000) employeeId,orderId from order
集算器A
1=connect("hsqlDB")
2=A1.query("select * from order")
3=A2.new(if(employeeId==null,1000,employeeId):employeeId,orderId)
4>A1.close()

集算器(SPL)≠SQL

看完上面这些例子,会给人一个感觉:集算器,或者其中的SPL代码只是 SQL 的替代品,而常用的关系数据库系统(RDBMS)本身已经是存储能力(数据表)+ 计算能力 (SQL) 的综合体了,还要这么一个外来的计算体系干嘛?

针对这个疑问,有两个层面的答案。首先是数据层面,并非所有要计算的数据都在数据库里。当你手边有个文本、excel 或从一个网络服务临时得到一些数据想要计算,或者从大量终端采集上来的数据马上要处理出结果……如果这些都不得不倒腾到数据库里然后再计算,还真是有点太绕了,更何况还可能涉及到数据库的安装部署,或者权限控制等琐碎而现实的问题。

其次是计算层面,对于很多复杂的计算过程,SQL 因为天生缺陷无法做到开发高效、维护高效、执行效高。这也是我们这篇文章最想说明的地方,SQL 的计算主要还是面向查询,而这些对"高效"的追求,面向的是更广泛的数据计算,这正是集算器和SPL语言所要重点改善的。

正因为有了这两个层面的原因,集算器和SPL语言已经可以独立于各种数据存储形式,在"存储"和"应用"之间,作为一个功能完整、形式灵活、部署方便的"数据计算中间件"而存在。这方面的内容,我们会在后面的章节做更多的介绍和探讨。

这里,我们只是先简单看一下集算器和SPL语言如何基于文本、Excel 等数据源进行计算。事实上,前面这些例子中的计算步骤完全不用改写,只需要改变加载数据那一句就可以了。也就是把:

=A1.query("select * from order")

改为下列任意方式之一:

=file("d:/data/order.txt").import@t()// 从文本文件加载数据表

=file("d:/data/orderDetail.xls").importxls@t()// 从 excel 加载数据表

=httpfile(" http:/ /127.0.0.1/service "," param1=value1¶m2=value2″) // 从 http server 加载数据表

……

很明显,通过这种简单明了的数据加载方式,可以将各种数据源的数据形成统一的"序表",从而在一个计算过程里可以轻松混合使用。换句话说,不必为了计算能力而要求必须统一存储方式。同样的,在集算器和SPL的环境中,计算结果的存储,也和加载数据一样方便,也是多样化的,可以由程序员自由选择。


数据 结果 两个 字段 复杂 函数 例子 运算 结构 语法 语言 存储 查询 层面 折扣 数据库 数据表 方式 步骤 雇员 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网科技名片 广州万易互联网科技有限公司 云之行互联网科技 互联网中国科技 深圳互联网络科技有限公司 互联网科技媒体 苏州大垚互联网科技 居家互联网科技有限公司 四个字互联网科技公司取名 中正互联网科技招聘 开启互联网科技时代小说 广州慧亚互联网科技怎么样 以后互联网后是啥科技 成都铂石互联网科技做什么的 互联网新科技动漫ppt素材 华夏恒生科技与互联网科技 福建互联网展示科技馆设计 科技互联网经济论坛 北京品多多互联网科技有限公司 互联网企业和网络科技有限公司 深圳恒合互联网络科技有限公司 互联网科技美容 互联网科技公司实习生 中国互联网十大科技股排名 科技类公司包括互联网吗 滨湖区互联网智能科技产品有哪些 互联网方面的科技前沿 本届互联网大会上的黑科技 互联网金融运营模式中的金融科技 前海云享互联网科技
0