集算器的组表使用特殊的格式来存储,组表文件的扩展名通常是ctx。下面先通过一个例子来了解组表的生成及其基本使用:
| 
   
  | 
  
   A  | 
  
   B  | 
 
| 
   1  | 
  
   =demo.query("select NAME, SURNAME, GENDER from employee")  | 
  
   
  | 
 
| 
   2  | 
  
   =A1.select(GENDER=="M")  | 
  
   =A1\A2  | 
 
| 
   3  | 
  
   =A2.(NAME).id()  | 
  
   =A3.len()  | 
 
| 
   4  | 
  
   =B2.(NAME).id()  | 
  
   =A4.len()  | 
 
| 
   5  | 
  
   =A1.(SURNAME).id()  | 
  
   =A5.len()  | 
 
| 
   6  | 
  
   [Sales,Technology,R&D,Financial,Admin]  | 
  
   [0,0.5,0.75,0.9,0.97,1]  | 
 
| 
   7  | 
  
   =to(100000).new(#:EID,A6(B6.pseg(rand())):Dept, if(rand()<0.5,"F","M"):Gender, if(Gender=="M",A3(rand(B3)+1), A4(rand(B4)+1))/" "/A5(rand(B5)+1):Name)  | 
  
   
  | 
 
| 
   8  | 
  
   =A7.select(Dept=="Sales")  | 
  
   =A8.len()  | 
 
| 
   9  | 
  
   2023-01-01  | 
  
   =workdays(A9,A9+365)  | 
 
| 
   10  | 
  
   =B9.((a=string(~,"yyMMdd"), to(rand(1000)+ 500).new(a/string(#, "0000"):OID, B9.~:Date,A8(rand(B8)+1).EID:EID, rand(100)*10+200:Amount))).conj().sort(EID, OID)  | 
  
   =A10.groups(EID;count(~):OCount, sum(Amount):OAmount)  | 
 
| 
   11  | 
  
   =file("D:/file/dw/employees.ctx")  | 
  
   =A11.create(#EID,Dept,Gender, Name)  | 
 
| 
   12  | 
  
   
  | 
  
   >B11.append@i(A7.cursor())  | 
 
| 
   13  | 
  
   =B11.attach(stable,OCount,OAmount)  | 
  
   >A13.append@i(B10.cursor())  | 
 
| 
   14  | 
  
   =file("D:/file/dw/orders.ctx")  | 
  
   =A14.create@p(#EID, OCount, OAmount)  | 
 
| 
   15  | 
  
   
  | 
  
   >B14.append(B10.cursor())  | 
 
| 
   16  | 
  
   =B14.attach(otable,#OID,Date,Amount)  | 
  
   >A16.append(A10.cursor().new(EID, OID,Date,Amount))  | 
 
| 
   17  | 
  
   >B11.close()  | 
  
   >B14.close()  | 
 
A1中从demo数据库中取出员工资料,并在A3和A4中分别整理出男女员工的名字,在A5中整理出员工的姓,准备用来随机成姓名。
A6中列出可选的部门名称,在B6中设置测试数据中各个部门员工的累积占比。如销售部Sales员工占比0.5,财务部Financial员工占比0.97-0.9=0.07,等等。
A7中随机生成了100,000位员工的测试数据,结果如下:
A8中从中选择出了销售部的员工,准备用来生成订单的测试数据:
B9中简单生成了2023年的工作日序列,作为测试数据中的订单日期。A10中在每个工作日中随机生成订单数据,并按照EID和OID排序,结果如下:
B10中统计出销售部每位员工的订单总数和总金额,如下:
现在,数据已经准备好了,可以来看组表是如何生成了。B11中,用f.create(C1,C2,…) 函数在组表文件employees.ctx中,生成了组表中的第一个实表员工实表,并定义了它的字段,其字段和A7中的员工数据是完全相同的。在组表中,员工实表不依附于任何表,它被称为基表,组表中有且仅有一个基表。其中,用#开头的字段是实表的维,维由实表中的某些列构成,实表中的记录对于维必须是有序的。组表employees.ctx的基表中定义了1个维EID,表示员工的编号,另外还有其它的一些字段,包括部门Dept、员工性别Gender和员工姓名Name。
组表默认将按列存储,如果需要按行存储,可以在create函数后添加@r选项。如果需要在组表中执行某条或某几条数据的查询,可以选择按行存储,以便于在查询时获得更好的性能,但行式存储的组表不便于处理整表的遍历计算,也不支持用多路游标访问数据。组表中的数据将压缩存储,以节省磁盘空间,如果不需要压缩可以在create函数后添加@u选项。如果生成组表时,指定名称的文件已存在,会失败报错,添加@y选项可以强制覆盖。
在B12中用T'.append(cs) 函数,用A7中的员工数据表构成游标,填入组表的基表中。使用T.append(cs) 函数时,必须保证cs的数据结构与实表T相同,这里的数据结构相同是指字段数和字段名称都要一致,否则添加数据时会产生错误。这里填入数据时使用了@i选项,立即将数据写人实表,如果没有使用这个选项则会积累到足够数据后执行写入,或者在组表用T'.close() 函数关闭时写入。在使用T.append()函数添加数据时,组表T不允许在多个位置打开,以防止数据冲突。
A13中用T.attach(T',C1,…)函数在同一个组表中,添加了实表stable,其字段包括订单个数OCount和订单总金额OAmount。类似的,在B13中将数据填入实表。需要注意的是,销售统计表stable是依附于基表,即员工实表的,是组表基表的附表,而相对的作为基表的员工实表称为stable的主表。附表除了具有自己的字段,还必须包括主表的键字段,因此填入数据时,B10中的数据也必须具备前表的键EID。
再来看14~16行,B14中定义了组表orders.ctx的基表销售员实表的字段,这个基表中定义了1个维:销售员编号EID。特别的,这里使用了@p选项存储时按首个字段EID分段,防止在分段读取时将同一个销售员的订单数据拆分。
B15中将销售统计表数据填入组表orders.ctx的基表。
A16中在组表中添加了订单实表otable,B16填入A10中的订单数据。
在组表orders.ctx中,订单实表otable,是依附于基表销售员实表的,是销售员实表的附表,相对的组表的基表销售员实表是otable的主表。在这个组表中,主表的键只有1个EID,而附表otable除了要具备主表的键EID外,还多一个键OID。这种情况下,主表与附表是主子表关系。
从上面的例子中可以了解,组表有可能包含多个实表,组表中的多个实表必须构成主表和附表的关系,其中有且仅有1个基表。组表使用后,在第17行中被关闭,关闭时只需关闭基表即可,如果组表使用时并未被写入则也可以不执行关闭。