SPL:一对多连接
连接(JOIN)用于把来自两个或多个表的记录结合起来。本文将探讨对于连接问题,SPL 的解决方案和基本原理。
表之间存在的数据相互依赖关系,就叫做表间关联关系。表间关联关系可以分为以下几种:一对一、多对一、一对多和多对多。我们可以通过表间关联关系,把两个或多个表连接起来,从而实现多表关联查询的目的。
一对多关联,是指一张表的一条记录能与另外一张表的任意记录进行对应。在一对多的关系中,我们把“一”的这端表叫做主表,“多”的这端表叫子表(从表)。例如有订单表和订单明细表,每笔订单对应唯一的订单 ID,但是每个订单 ID 可能对应多条订单明细信息。我们称订单表是主表,订单明细表是子表。
【例 1】 根据订单表和订单明细表,统计每个订单的总金额。部分数据如下:
ORDERS:
ID | CUSTOMERID | EMPLOYEEID | ORDER_DATE | ARRIVAL_DATE |
10248 | VINET | 5 | 2012/07/04 | 2012/08/01 |
10249 | TOMSP | 6 | 2012/07/05 | 2012/08/16 |
10250 | HANAR | 4 | 2012/07/08 | 2012/08/05 |
10251 | VICTE | 3 | 2012/07/08 | 2012/08/05 |
10252 | SUPRD | 4 | 2012/07/09 | 2012/08/06 |
… | … | … | … | … |
ORDER_DETAIL:
ID | ORDER_NUMBER | PRODUCTID | PRICE | COUNT | DISCOUNT |
10814 | 1 | 48 | 102.0 | 8 | 0.15 |
10814 | 2 | 48 | 102.0 | 8 | 0.15 |
10814 | 3 | 48 | 306.0 | 24 | 0.15 |
10814 | 4 | 48 | 102.0 | 8 | 0.15 |
10814 | 5 | 48 | 204.0 | 16 | 0.15 |
… | … | … | … | … | … |
单个主子表时,可以使用函数 join(), 通过子表的部分主键与主表主键进行连接。
SPL脚本如下:
A | |
1 | =T("Orders.txt") |
2 | =T("OrderDetail.txt") |
3 | =join(A1:Orders,ID; A2:Detail,ID) |
4 | =A3.groups(Orders.ID; sum(Detail.PRICE*Detail.COUNT):AMOUNT) |
A1:导入订单表。
A2:导入订单明细表。
A3:订单表和订单明细表通过订单 ID 进行连接。
A4:分组汇总每个订单的总金额。
【例 2】 订单表还有一个子表用于记录回款情况。我们现在想知道哪些订单还没有收到全部回款,也就是累计回款金额小于订单总金额的订单。部分数据如下:
ORDERS:
ID | CUSTOMERID | EMPLOYEEID | ORDER_DATE | ARRIVAL_DATE |
10248 | VINET | 5 | 2012/07/04 | 2012/08/01 |
10249 | TOMSP | 6 | 2012/07/05 | 2012/08/16 |
10250 | HANAR | 4 | 2012/07/08 | 2012/08/05 |
10251 | VICTE | 3 | 2012/07/08 | 2012/08/05 |
10252 | SUPRD | 4 | 2012/07/09 | 2012/08/06 |
… | … | … | … | … |
ORDER_DETAIL:
ID | ORDER_NUMBER | PRODUCTID | PRICE | COUNT | DISCOUNT |
10814 | 1 | 48 | 102.0 | 8 | 0.15 |
10814 | 2 | 48 | 102.0 | 8 | 0.15 |
10814 | 3 | 48 | 306.0 | 24 | 0.15 |
10814 | 4 | 48 | 102.0 | 8 | 0.15 |
10814 | 5 | 48 | 204.0 | 16 | 0.15 |
… | … | … | … | … | … |
ORDER_PAYMENT:
ORDER | PAY_DATE | AMOUNT | CHANNEL | INSTALMENTS |
10814 | 2014/01/05 | 816.0 | 3 | 0 |
10848 | 2014/01/23 | 800.25 | 2 | 1 |
10848 | 2014/01/23 | 800.25 | 0 | 0 |
10848 | 2014/01/23 | 800.25 | 3 | 1 |
10966 | 2014/03/20 | 572.0 | 2 | 1 |
… | … | … | … | … |
简单地把这三个表 JOIN 起来是不对的,订单明细和订单回款表会发生多对多的关系。
子表对着订单 ID 分组后,订单 ID 就变成了具有唯一性的事实上的主键。然后我们就可以把这些表通过订单 ID 进行连接,当作一对一(同维表)关系来处理了。
SPL脚本如下:
A | |
1 | =T("Orders.txt") |
2 | =T("OrderDetail.txt") |
3 | =T("OrderPayment.txt") |
4 | =A2.groups(ID; sum(PRICE*COUNT):AMOUNT) |
5 | =A3.groups(ORDER; sum(AMOUNT):PAY_AMOUNT) |
6 | =join(A1:Orders,ID; A4:Detail,ID; A5:Payment,ORDER) |
7 | =A6.new(Orders.ID, Detail.AMOUNT, Payment.PAY_AMOUNT) |
8 | =A7.select(PAY_AMOUNT<AMOUNT) |
A1:导入订单表。
A2:导入订单明细表。
A3:导入订单回款表。
A4:分组汇总每个订单的总金额。
A5:分组汇总每个订单的回款总金额。
A6:使用函数 join() 将订单表和汇总后的明细表、回款表按照订单 ID 连接。
A7:创建由字段订单 ID、订单金额和回款金额组成的序表。
A8:从中选出回款金额小于订单金额的记录,即还没有完全付清的订单。
SPL在处理一对多关联(主子表)时大体上分为两步:第一步, 所有子表按照部分主键(主表的主键)进行分组,此时所有子表的事实主键与主表相同了。第二步, 将多个表按照其主键(或事实主键)进行连接。
英文版