SQL的join语句比较抽象,只适合表达较简单的关联关系,一旦关联的层级较多,相应的代码就会变得很复杂。集算器可以用对象引用表达关联关系,代码更加直观,下面用一个例子来说明。
? 表channel存储着某网站所有的频道及其上级频道的对应关系,分别用id和parent字段来表示,最多四级,其中root代表网站本身(即根节点)。请根据输入参数列出某频道的下一级、下两级、下三级频道的名字,用逗号分隔。表channel中的部分数据如下:
?
集算器代码:
?
A1:查询表channel,命名为data,部分结果如下:
?
B1=data.switch(parent,data:id),这句代码用来建立自连接。代码中使用了函数switch,它作用是将parent字段切换成data中对应的记录,如下图所示:
?
切换后,可以直接用parent.id来表示上级频道,parent.parent.parent.id则表示上三级频道。SQL可以用join来表示这种自连接,但层级一多就会混乱。
A2=create(id,level,sub),这句代码建立了一个空序表,用来存储最终的计算结果。与显式定义的变量data不同,格名A2就是这个序表的默认变量名。A2的当前值如下:
?
A3=data.select(parent.id==arg1 ),这句代码从data中查询出上级频道等于参数arg1的记录,即:arg1的下一级频道。其中arg1是事先定义的外部参数,可以来自JAVA或报表。假如参数arg1的值为p1,则A3的计算结果如下:
?
B3=A2.insert(0,arg1,1,A3.(name).string()),这句代码在A2中追加一条记录,第一个字段值是arg1(假设是p1);第二个字段值为1,表示第一级子频道;第三个字段为表达式A3.(name).string(),这表示取出A3中的列name,拼成逗号分隔的字符串。计算结果如下:
?
A4=data.select(parent.parent.id==arg1),这句代码和A3类似,表示从data查询出arg1的下两级频道。结果如下:
?
A5和A4类似,表示取出arg1的下三级频道。用类似的办法可以轻松取出下N级的频道。
B4、B5和B3类似,都是向A2中追加新记录,只是level字段改为2和3。执行完B5后,A2就是本次运算的最终结果:
?
刚才参数arg1的值为p1,如果输入c11,则计算结果如下:
?
有时我们希望看到更清晰的数据,比如将某个频道的所有下级频道一条条列出,并标出层级关系。要想实现这种算法,可以使用下面的代码:
?
红色字体为变动后的代码,其中B3中的代码是=A2.insert(0,arg1,1,A3),这表示直接将A3的记录存储在A2中,假设参数arg1的值为p1,则计算结果如下:
?
点开sub字段,可以看到详细的记录:
?
可以看到,集算器的字段值是泛型的,可以存储记录组,或者单条记录。值得注意的是,函数switch的本质就是将外键切换为主表中的单条记录。
执行完B5后,A2中的结果如下:
?
A6=A2.(~.sub.new(A2.id,A2.level,id:subid,name)),这句代码用来将A2中id和level拼到sub字段里的每条记录中。其中A2.()表示对A2进行计算,计算中可以使用“~”来表示A2中的每条记录,~.sub则表示每条记录的sub字段(记录组)。函数new用来生成新的序表,即:A2中的id字段、level字段,sub中的id字段、name字段。计算完成后,A6的值如下:
?
A7=A6.union(),这句代码用来将A7的各组记录拼在一起,形成最终计算结果:
?
有时我们需要直接列出每个频道的所有下级频道,而不是使用参数。要想实现这种算法,可以使用集算器的for语句,代码如下:
?
A3中的代码for data.(id)表示循环data的id字段,每次取出一条,可以用循环语句所在的单元格A3来表示循环变量。循环的作用范围可以用缩进来表示,即B 4-C6。最终的计算结果在A8中,部分数据如下:
?
另外,集算器可被报表工具或java程序调用,调用的方法也和普通数据库相似,使用它提供的JDBC接口即可向java主程序返回ResultSet形式的计算结果,具体方法可参考相关文档。