组表保存到文件后,可直接用f.open() 函数打开,如:
|
A |
B |
1 |
=file("D:/file/dw/employees.ctx") |
|
2 |
=A1.open() |
=A2.cursor().fetch() |
3 |
=A2.attach(stable) |
=A3.cursor().fetch() |
4 |
|
=A3.cursor(EID,Dept,Gender,Name,OCount,OAmount).fetch() |
5 |
>A2.close() |
|
在A2中,使用f.open函数打开组表的基表,在A3中,仅指定附表的名称,用T.attach(T')函数打开主表T的附表T',可对附表做更新或修改。在B2中查询出组表基表中数据如下:
这里获得的数据和前面填入组表中的数据是相同的,可以看到其中EID为主键。
B3中查询出附表stable中数据如下:
从附表中查询的数据也可以包括主表中的字段,如B4中生成游标时,同时取出了主表中的字段,结果如下:
在上面的例子中从实表中查询数据时,使用了T.cursor() 函数,实际上,在使用函数T.cursor(C1, C2…; w)从实表T中查询数据时,还可以设置从实表中选取的字段C1, C2…或者查询条件w,如:
|
A |
B |
1 |
=file("D:/file/dw/employees.ctx") |
|
2 |
=A1.open() |
=A2.attach(stable) |
3 |
=A2.cursor(EID,Name,Dept) |
=A3.fetch() |
4 |
=A2.cursor(;right(Name,1)=="e") |
=A4.fetch() |
5 |
=B2.import(EID,Name,OCount,OAmount) |
>A2.close() |
A3中仅从组表的基表中取出部分字段,B3中fetch获得的结果如下:
A4中设置了查询姓名最后一个字母为e的员工数据,B4中获得的结果如下:
如果需要把实表中满足条件的数据全部取出,可以使用函数T.import(C1, C2…; w)。A5中从实表stable中取出销售员数据,A5中获得的结果如下:
当组表中的数据较多时,也可以分段读取数据,此时首先需要将组表分段存储。在分段存储时,需要指明分段依据的字段。下面来了解实表中数据分段存储和分段读取的情况:
|
A |
B |
1 |
=file("D:/file/dw/employees.ctx") |
=A1.open() |
2 |
=B1.attach(stable) |
|
3 |
=file("D:/file/dw/orders.ctx") |
=A3.open() |
4 |
=B3.attach(otable) |
|
5 |
=A2.cursor(;;1:3).fetch() |
=A2.cursor(;;2:3).fetch() |
6 |
=A4.cursor(;;1:3).fetch() |
=A4.cursor(;;2:3).fetch() |
7 |
>B1.close() |
>B3.close() |
A2中从组表文件employees.ctx中取出销售员实表stable,A5和B5中,从销售员实表中分段取数,都分为3段,但分别取出第1段和第2段,结果分别如下:
和上一个例子中,A5中的销售统计数据对比可以发现,第1段最后的销售员序号32768,和第2端最初的销售员序号32770是相邻的销售人员序号,这说明,在分段读取时,数据能全部被遍历,同时又不会重复被读取。
A4打开组表文件orders.ctx中的订单实表otable,A6和B6中,从订单实表中分段取数,同样分为3段,并分别取出第1段和第2段,结果分别如下:
首先,因为otable中数据更多,所以分段读取后,每段读取到的记录数量也更多。其次,由于在存储orders.ctx时,设定了按EID分段,因此分段时会把相同销售人员的订单分在同一段,保证第1段末尾与第2段开头的记录属于不同的销售人员。同时,与B5和B6中的数据对比可以发现,在使用不同的组表文件时,由于数据本身存在差异,分段的情况并不一定相同,如销售员数据的第2段首条记录的EID为32770,而订单数据第2段的首条记录的EID为32809,分段情况是不同的。
在使用多个组表中的实表时,需要避免分段的不同步,此时,可以使用多路游标进行同步。如:
|
A |
B |
1 |
=file("D:/file/dw/employees.ctx") |
=file("D:/file/dw/orders.ctx") |
2 |
=A1.open() |
=B1.open() |
3 |
=A2.attach(stable) |
=B2.attach(otable) |
4 |
=A3.cursor@m(;;3) |
=B3.cursor(;;A4) |
5 |
=joinx(A4:s,EID;B4:o,EID) |
=A5.fetch() |
6 |
=A3.cursor@m(;;3) |
=B3.cursor(;;A6) |
7 |
=joinx(A6:s,EID;B6:o,EID) |
=A7.groups(s.EID:EID;count(~):Count, sum(o.Amount):Sum) |
8 |
>A2.close() |
>B2.close() |
A3和B3中,分别在两个不同的组表中,读出实表stable和实表otable。在A4中,用函数T.cursor@m(;;n) 将实表stable分为n段生成多路游标,在B4中用实表otable根据A4中的多路游标同步分段。执行同步分段后,在A5中将A4和B4中的游标用joinx函数将同步的多路游标连接起来,在B5中可以看到连接的结果:
从结果中可以看到,原本两个分段效果不同的游标,经过同步分段后,能够正确匹配。
在B7中,重新生成多路游标的连接,并计算出每个销售员的订单总数和销售总数,结果如下:
将结果与前面stable中的OCount和OAmount对照,可以确认连接的结果是正确的。
由于组表中的实表是可以分段读取的,因此实表也可以用于cs.joinx(C:…, T:K:…, x:F,…;…;n) 函数中,用实表T代替其中的可分段集文件f来与游标中的数据做连接计算。
在实表中,可以根据条件为其生成索引,如果使用索引来执行查询,效率会明显提高。如:
|
A |
B |
1 |
=file("D:/file/dw/employees.ctx") |
=A1.open() |
2 |
=B1.import(;) |
|
3 |
|
=now() |
4 |
=B1.cursor(;[8136,11247,83372,264,8223,826, 32758,1341,6255,1983].contain(EID)) |
=A4.fetch() |
5 |
|
=interval@ms(B3, now()) |
6 |
=B1.index(file("D:/file/dw/emp.idx"), [8136,11247,83372,264,8223, 826,32758,1341,6255,1983].contain(EID);EID) |
=now() |
7 |
=B1.icursor(;[8136,11247,83372,264,8223, 826,32758,1341,6255, 1983].contain(EID);file("D:/file/dw/emp.idx")) |
=A7.fetch() |
8 |
|
=interval@ms(B6, now()) |
9 |
>B1.close() |
|
第1、2行打开组表employees.ctx中的基表员工实表。在第4行,直接从实表中查询10条记录,B4中得到结果如下:
在A6中,用函数T.index(f:h,w;C,…;F,…) 为实表创建索引文件,索引文件名称为emp.idx,索引字段为EID。在A7中使用T.icursor(C,…;w;f,…)函数查询时,可以根据索引文件来执行。B7中得到的结果和B4中是相同的。
B5和B8中分别计算出两种情况下查询10条记录的耗时如下:
可以发现,使用索引时,查询效率会更高。另外,如果在组表是按行存储的,那么在使用索引查询时,能够获得更好的性能。
在组表中,如果使用了排号类型的字段作为键,可以使用排号键的部分字段作为分段键,以便在键中得到更多的信息,同时可以获得更高的效率,如:
|
A |
B |
C |
D |
1 |
=file("D:/file/dw/students.ctx") |
=create(ID,City,School, SID) |
|
|
2 |
for 20 |
="C"/A2 |
=20+rand(31) |
|
3 |
|
for C2 |
=B2/"_S"/B3 |
=rand(4001)+1000 |
4 |
|
|
for D3 |
|
5 |
|
|
|
>B1.insert(0,k(A2,B3,C4:2),B2,C3,C4) |
6 |
=A1.create@y(#ID,City, School,SID) |
>A6.append(B1.cursor()) |
=A1.open() |
|
7 |
=A6.import(;;10: 200) |
=A6.import(;;11: 200) |
>A6.close() |
|
在第2~6行,准备了组表中的数据,存储在B1的序表中。数据中,包含编号、城市、学校及学号等字段,创建了C1~C20共20个城市的学生数据,每个城市包含20~50个学校,而每个学校的学生数为1000~5000。数据中的编号ID字段使用了排号类型的数据,使用前4个字节存储信息,其中第1个字节记录了城市编码,第2个字节记录了学校编码,第3,4两个字节记录了学号。注意1个字节的取值范围是0~255,2个字节的取值范围是0~65535,注意几种数据的值不能超限。数据生成后,B1中数据如下:
A6中构建组表的基表后存入数据。A7中的数据如下:
B7中的数据如下:
比较这两段相邻的数据,可以发现相邻的两段都可能来自相同的城市或者学校,这样的数据使用不是很方便。为此,可以把组表中的数据按需要存储在不同的文件中,如:
|
A |
B |
1 |
=file("D:/file/dw/students.ctx") |
=A1.open() |
2 |
=file("D:/file/dw/students.ctx":to(20)) |
=B1.create(A2; int(ID.sbs(1))) |
3 |
=B1.cursor() |
>B2.append@x(A3) |
4 |
=file("D:/file/dw/students.ctx":2) |
=A4.open() |
5 |
=B4.cursor().fetch(100) |
>B4.close() |
6 |
=file("D:/file/dw/students.ctx":3) |
=A6.open() |
7 |
=B6.cursor().fetch(100) |
>B6.close() |
8 |
>B1.close() |
|
在A2中,用file(fn:zs) 函数生成文件组,其中fn为文件名,zs为数列,如果数列中有n个整数,文件组中会生成n个文件。而用文件组生成的组表称为复组表,复组表中的每个成员称为分表,都可以通过文件名和对应的分表号来单独访问。A2中使用了20个分表,对应20个城市。在B2中,利用前例的students.ctx组表结构,使用T.create(fg; x) 来生成复组表,其中fg是文件组,是x分表表达式,可以计算出一个整数对应某一个分表,复组表也可以用fg.create(C1,C2,…; x)函数来生成。B2中,通过排号键ID来获取城市编号,用城市编号作为分表号。
B3中向复组表中写入数据,由于使用的数据来源于前例生成的组表,因此这里需要添加@x选项,说明游标中的数据可能对应多个分表,需要每次执行分号表达式判断。如果向复组表中写入数据时使用的是多路游标,则每路游标会一一对应一个分表,分号表达式就不会计算了。
A4中,用用file(fn:z) 函数获取单一分表文件,这里分表的文件名为students.ctx,分表号为2。根据分表表达式的设定,其中的数据存储的是第2个城市的,A5获取到的结果如下:
类似的,A6中获取第3个分表,A7得到其中数据如下:
可以看到,使用复组表,能够让数据更有效地存储在一系列文件构成的文件组中,访问和管理都会非常方便。这里例子中students.ctx为单一的组表,而复组表的存储时需要使用students.ctx和分表号共同构成的名称,文件夹中存储的情况如下:
如果组表与已有的排列或者游标中的数据相关,可以使用T.new(A/cs, x:C, …:w),T.derive(A/cs, x:C, …;w)或T.news(A/cs, x:C, …;w)使用,根据匹配条件取出实表T中的其它字段,生成新序表(游标)或者添加字段后生成新序表(游标),如:
|
A |
1 |
=file("D:/file/dw/employees.ctx") |
2 |
=A1.open() |
3 |
=create(EID,Salary).keys(EID).record([1,10000,147,12000,179,9800]) |
4 |
=A2.new(A3, EID, Dept, Name, Salary) |
5 |
=A2.new(A3.cursor(),EID, Dept, Name, Salary; Dept=="Sales").fetch() |
6 |
>A2.close() |
A3中新建了一个序表,包括主键EID和工资Salary两个字段,并插入了3条记录:
A4中使用T.new(A/cs, x:C, …:w)函数,取出EID,Dept,Name和Salary4个字段构成新序表返回,其中Dept和Name是员工组表中的数据。在函数计算时,会根据A3中序表的主键,在组表的实表中查询与之匹配的记录读取所需字段的值。注意序表相对于实表的主键必须是有序的。A4中结果如下:
A5在函数使用游标作为参数计算,则结果也会返回游标,需要用fetch取出结果,另外函数中还添加了过滤条件,只取出销售部的员工数据,结果如下:
可以看到,使用T.new(A/cs, …)时,序表或者游标中的数据不一定要与实表T属于同一组表,只是根据主键判断关联关系。
与此类似的函数还有T.news(A/cs, …),此时实表T通常是A或者cs的子表,也就是说序表或者游标中的每条记录,都会对应着实表T中的多条记录,也会在新序表中生成多条记录。此时实表T一般需有多个主键,而A或者cs的主键与T的部分主键对应。