7.4.2对齐式连接

在统计数据时,有时需要将多个游标中的数据整合在一起,这类似于连接多个表中的数据。如果是游标中的数据需要连接一个普通序表,可以使用cs.switch()

如果需要连接的数据都来自游标,情况又如何呢?我们知道,游标中的数据通常是无法一次读出的,那么如何将数据连接呢?在集算器中,可以使用joinx()函数来将多个游标中的数据连接起来。如:

 

A

1

=file("Order_Wines.txt").cursor@t()

2

=file("Order_Electronics.txt").cursor@t()

3

=file("Order_Foods.txt").cursor@t()

4

=file("Order_Books.txt").cursor@t()

5

=A1.groupx(Type,Date;count(~):Count,sum(round(decimal(Amount),2)):TotalAmount;100)

6

=A2.groupx(Type,Date;count(~):Count,sum(round(decimal(Amount),2)):TotalAmount;100)

7

=A3.groupx(Type,Date;count(~):Count,sum(round(decimal(Amount),2)):TotalAmount;100)

8

=A4.groupx(Type,Date;count(~):Count,sum(round(decimal(Amount),2)):TotalAmount;100)

9

=joinx@1(A5:Wines,Date;A6:Electronics,Date;A7:Foods,Date;A8:Books,Date)

10

=A9.fetch(25)

11

>A9.close()

A5~A8中,分别对每一类产品分类聚合运算,各自返回缓存文件游标。关于groupx的使用,在7.5外存分组原理中有更详细的说明。在A9中将各类产品每日的销售数据按照日期对齐连接。在A10中取出前25天的统计结果如下:

游标对齐式连接后,将返回游标,从中读出的结果和序表连接是类似的,每行数据的每个字段都是由记录构成的。因此,在读取时需要注意,连接后一行记录所占的内存会比普通情况更大。同时,由于数据均是记录而并非是值,如果使用结果游标进行计算时,要注意表达式的书写,特别是用结果游标再次连接时

游标对齐式连接的结果,也可以再用来继承,如筛选,生成等,如:

9

=joinx@1(A5:Wines,Date;A6:Electronics,Date;A7:Foods,Date;A8:Books,Date)

10

=A9.select(Foods.TotalAmount>Wines.TotalAmount)

11

=A10.new(Foods.Date:Date,Foods.TotalAmount:Foods,Wines.TotalAmount:Wines)

12

=A11.fetch(100)

13

>A11.close()

A10在连接的游标中,添加计算筛选出食品订单总额大于酒类订单总额的记录,并在A11中继续添加计算生成结果。在A12中返回了前100条结果,如下:

在使用游标的对齐式连接时,必须要知道,在取数时,游标中的数据是不能读取到内存中保留的,只能从前往后遍历记录一次。因此,连接计算中,各个游标中的数据必须是有序的,这和数据库中多表连接时的处理不同,也和普通序表的join() 不同。如上面的例子,A5~A8中的数据均是对日期有序的,这样才能保证在连接时的计算正确。

为了更好地说明这个问题,下面用数据较少的两个内存序表构成游标,来了解一下:

 

A

1

$select * from CITIES

2

$select * from STATES

3

=A1.cursor()

4

=A2.cursor()

5

=joinx(A3:City,STATEID;A4:State,STATEID)

6

=A5.fetch()

其中,A1A2中的序表分别如下:

此时,A6中,对齐连接后结果如下:

游标中的数据是与普通序表不同的,在连接时,当寻找纽约市所对应的纽约州时,州数据中的游标就已经移到了第32条,在后面的计算中无法再找到之前的记录。这样,就使得大多数的城市无法找到对应的州。由于joinx() 函数中未使用@1@f选项指定左连接或全连接,仅返回找到对州的城市,数据非常少。

如果先将数据排序,就可以获得比较正常的连接结果了:

 

A

1

$select * from CITIES order by STATEID

2

$select * from STATES order by STATEID

3

=A1.cursor()

4

=A2.cursor()

5

=joinx(A3:City,STATEID;A4:State,STATEID)

6

=A5.fetch()

此时A1中获得的是按州序号排序后的城市数据:

在这种情况下,A6中结果如下:

在将游标中的数据做连接时,并不需要游标的种类相同,如:

 

A

1

=file("PersonnelInfo.txt")

2

=A1.cursor@t().sortx(State)

3

$(demo) select STATEID, NAME, ABBR from STATES order by ABBR

4

=A3.cursor()

5

=joinx(A2:PersonnelInfo,State;A4:State,ABBR)

6

=A5.fetch(100)

7

>A5.close()

A5中将员工信息与对应的州记录连接。需要注意的是,连接之前要保证游标中的数据完成了排序。A6中获取前100条数据如下:

实际上,在将不同游标中的数据做连接时,往往是为了获取其它游标中的相关信息。如上例中,如果只是为了获取员工所在州的全名,而州数据其实是来自于序表的,那么还可以不将游标中的记录互相做关联,而是选择使用cs.switch(),将游标cs中的某个字段做对应的记录转换。关于在游标中使用switch的方法,可以阅读7.2游标使用。使用joinx()cs.switch()的不同之处在于,joinx()是将游标中的数据相互连接,而cs.switch()是将序表或序列作为维表,与游标中的字段做外键式关联。由于joinx()是游标之间的运算,因此要求游标中的数据对于连接字段是有序的。而cs.switch()使用的维表都存储在内存中,因此不要求有序。

有的时候,在处理外键式关联时,需要用多个外键字段联合起来,对应一个序表或者游标中的数据,此时可以用cs.join()来用连接的方式添加字段。如:

 

A

1

=file("PersonnelInfo.txt")

2

=A1.cursor@t()

3

$(demo) select STATEID, NAME,ABBR from STATES

4

=create(Month,State,GroupID)

5

>A3.(12.((m=~,A4.insert(0,m,A3.ABBR,A3.ABBR+string(m)))))

6

=A2.join(month(Birthday):State,A4:Month:State,GroupID:Group)

7

=A6.fetch(100)

8

>A6.close()

A4中根据月份及州的简称创建序表,A5填入数据后,A4中序表如下:

A6中,通过连接的方式,在游标A2中添加字段,添加时,用A2游标中的员工生日月份及State,和序表A4中的MonthState做等值连接,连接后,取出A4x序表中的GroupID字段添加到结果中的State字段中。从A7中读取前100条结果如下:

在使用cs.join()时,可以用序表与cs的字段连接,与joinx()不同,使用cs.join()时并不要求cs中的数据有序。本例中,需要将cs中的两个字段与维表做连接,这种情况是无法用cs.switch()解决的。