SPL的基本使用
SPL的基本使用
安装SPL
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<exclusions>
<exclusion>
<groupId>com.vaadin.external.google</groupId>
<artifactId>android-json</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.scudata.esproc</groupId>
<artifactId>esproc</artifactId>
<version>20220601</version>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.2.8</version>
</dependency>
<dependency>
<groupId>com.ibm.icu</groupId>
<artifactId>icu4j</artifactId>
<version>60.3</version>
</dependency>
<dependency>
<groupId>org.lucee</groupId>
<artifactId>jdom</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.2</version>
</dependency>
<dependency>
<groupId>org.apache.xmlbeans</groupId>
<artifactId>xmlbeans</artifactId>
<version>5.1.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.0.6.RELEASE</version>
</plugin>
</plugins>
</build>
- 安装java环境,最低1.8版本
- 下载SPL社区版,官方下载网站
- 目录结构
ESPROC-20240926_ZH
└─raqsoft
├─common
│ └─jdbc
└─esProc
├─backup
├─bin
├─classes
│ └─config
├─config
├─database
│ └─demo
├─demo
│ ├─en
│ │ ├─Nonstructural
│ │ └─txt
│ └─zh
│ ├─Nonstructural
│ ├─Structural
│ └─txt
├─documents
│ └─zh
├─lib
├─log
├─logo
└─update
其中还有一个部署说明
windows中
若架构不是x86或者改java版本(压缩包中默认提供jre1.8),需要修改raqsoft/esProc/bin/setEnv.bat文件中的JAVA_HOME设置为java的路径,若系统配置了该环境变量,这里可以省略
数据类型
基本数据类型
实数(number),包括整数、长整数、浮点数、长实数这四种类型,可用类型转换函数number()将其它类型数据转换为实数。
- 整数(int),可用类型转换函数int()将其它类型数据转换为32位整数
- 长整数(long),可用类型转换函数long()将其它类型数据转换为长整数
- 浮点数(float),64位浮点数,这是集算器中最常用的数据类型,涉及小数的运算基本都是用它来计算的,可用类型转换函数float()将其它类型数据转换为浮点数。由于浮点数是用二进制规则存储数据的,因此在计算中有可能出现误差。
- 长实数(decimal),可以无误差地存储任何十进制实数,但是使用长实数计算时,需要消耗更多的内存,且计算的效率较低。可用类型转换函数decimal()将其它类型数据(如字符串)转换为长实数
布尔型,包括true/false
字符串(string),用双引号括起来,其中转义字符用\。可以用函数string()将其它类型的数据转换为字符串
Amy ## Amy, 直接定义字符串常量时,不用引号 ="State:\tTX" ## State: TX ="Texas" "Dallas" ## TexasDallas, 计算两个字符串x与y合并,可以在之间添加空格x y =A1+3.14 ## 3.14, 也可以直接用加法,写作x+y,但是此时x与y必须均为字符串,如果其中之一为实数,结果即为实数而不是字符串 =A1/3.14 ## Amy3.14, 将实数作为字符串,与其它字符串连接,可以用x/y,来计算,此时如果x与y其中之一为字符串,结果即为字符串日期/时间(date/time/datetime),可以用类型转换函数date(),time()和datetime()将字符串或者长整数转换为日期,时间或者日期时间类型。
排号:不理解(官方说明)
集算器中,布尔型、字符串及日期时间数据,都会靠左对齐,显示为黑色。
数据类型的判断
- ifnumber(x):判断x是否是实数
- ifstring(x):判断x是否是字符串
- ifdate(x):判断x是否是日期类型或日期时间类型
- iftime(x):判断x是否是时间类型
序列
序列是有序的泛型集合
集合性:成员可以是任意数据类型,比如字符串、数字、浮点、日期,序列成员还可以为空。序列具有集合的一般特性,可以进行集合运算
[] [5,6,7] [red,blue,yellow] =["blue","yellow","white"] =A3^A4 //SPL code from泛型性:序列是泛型集合,成员的数据类型可以不同,成员本身也可以是序列
有序性:顺序不同的两个集合不相等
操作
- 生成
- 常数构造
[],其中可以添加成员 - 函数构造
- 常数数列
=to(2,6) - 字符串拆分为序列
="1,a,b,c".split@c()- @c:按逗号切分
- 日期间的日期序列
=periods@yx("2014-08-10",date(2018,2,1))- @y选项表示以年为间隔
- @x选项表示不包括后端点。
- 从文件中读取序表(特殊的序列)
=file("sales.txt").import@t()
- 常数数列
- 计算生成
- 取出某列
=A1.(STATE) - 分组
=A1.group(STATE),结果为序列中的序列
- 取出某列
- 常数构造
- 获取成员
- 取出一个
=A1(2)或=A1.m(2) - 取出多个
=A1([2,3,4])或=A1(to(2,4)) - 取出序列中的倒数第1个成员
=A1.m(-1)。注意,倒取数时必须用A.m()函数,不能简写为A1(-1) - 用A.m()函数可以访问多个成员
=A1.m(2,-2)- 还可以指定某几个区间
=A1.m(2:4,3:5)
- 还可以指定某几个区间
- 取出一个
- 插入、删除、修改、复制、比较、聚合、子序列、排序、排名、集合运算、字符串和序列互转
- 交
=A3^A4、差=A3\A4、并、补
序表
序表是有结构的序列,继承了关系数据库中的数据表概念,与关系数据库的概念一致,每个序表也有其自身的数据结构,由若干字段构成。序表的成员被称为记录
有结构的二维数据对象
序列的成员可以是任意数据类型,比如普通类型、其他序列或者记录。而序表的成员一定是记录,且每条记录的结构相同
序表通常生成自SQL、文本文件、集文件、Excel文件,也可以由空白序表创建而来
=file("Order_Books.txt").import@t() =demo.query("select * from CITIES") =create(OrderID,Client,SellerId,Amount,OrderDate) //SPL code from
操作:
查询
=A1.select(Amount>=20000 && month(Date)==5)排序
=A1.sort(SalesID,-Date)求和,平均值,合并重复记录
特殊的序列
- 序列的集合性、有序性及其相关的函数都适用于序表
排列
用某种数据对象来存储原序表中部分记录的引用,这种数据对象就是排列。
- 透明性
- 用户不必刻意区分排列和序表,就像不必刻意区分引用和实体数据。比如前面例子中的查询、排序、交集等算法既可以用于排列也可以用于序表,语法上完全一样
- 对序表做集合运算通常没有实际意义,其交集恒定为空
- 如果数据结构发生了变化,集算器会自动生成新序表,比如用groups函数计算分组汇总,或者用derive函数在序表中添加字段时
- 序表会单向影响排列:排列是序表记录的引用,它们具有相同的实体数据,修改了序表会影响排列
- 为了避免这种影响,用户应当在生成排列前就完成对序表的修改
- 操作
- 生成排列
=A1.to()
- 生成排列
单元格
常数格
- 单元格能将格串解释为一个常数,那么这个单元格被称为常数格,它的格值就是这个常数
- 文字显示为粉色
- 根据格子中的数据,会解析为各种数据类型,如整数型,浮点数型,日期型等,如果无法理解,会把单元格中的格串解释为字符串。
- 常数单元格中定义字符串,不必使用双引号。
- 在常数单元格中,可以使用百分数的表示法,如5%,该写法只能在常数单元格使用,其他时候使用0.05来表示。
- 常数格中的值还可以是true,false或者null
- 字符串常数格的格串是以英文单引号'开头的,字符串显示时下方会有下划线,而默认字色也和数值不同
序列常数
- 定义序列常数,只需要用[]表示,序列的成员中间用,分隔
- 定义序列常数时,序列中的字符串成员同样不必用双引号标明,测试发现序列中数据类型可以不一致
常数序列单元格
可以是一行
1 2 4 8 16 32
=[A1:F1]
//SPL code from
可以是一列
1
8
=[A1:A2]
//SPL code from
可以是一片
1 2 4
8 16 32
=[A1:C2]
//SPL code from
输出结果和序列常数相同
将一片常数单元格填入新的序表,使用这种方法,可以用脚本文件存储表格数据
German 2 1 0 7
American 1 1 1 4
Portugal 1 1 1 4
GHana 0 1 2 1
=create(Team,W,D,L,Points) //创建表头
>A5.record([A1:E4]) //在A5中写入数据,要查看效果需要点击A5单元格
//SPL code from
1 2 4
8 16 32
=[A1:C2]
//SPL code from
计算格
- 以= 开头的计算表达式的单元格称为计算格,其格值即为该表达式的计算结果
- 在表达式中,可以使用各种基本操作符计算格值:加减乘除、取余()%)、取整(\)
加号 or 连接符
s1+s2 连接字符串s1和s2。需要注意的是,如果字符串与实数相加,字符串将被忽略。
="Stephen"+" "+"Rolfe" 字符串Stephen Rolfe
="A"+3 整数3,字符串"A"被忽略
="A"+string(3) 字符串A3,如果确实需要连接字符串和实数,需要先将实数转换为字符串
执行格
- 格串以>开头的单元格称为执行格,用于执行某种操作
- 执行格没有格值
- 执行格以保留字作为开头时,如if、for等,>省略不写
- 执行格的代码可以修改其它单元格的值,可以将单元格用作变量
注释格
格串以/开头的单元格称为注释格,其格值为空
参数
函数参数的分隔符
使用 冒号: 逗号, 分号; 作为函数参数的分隔符,优先级依次降低。
逗号分隔多个参数的方式是最常见的,这与大多数程序语言中的函数语法是相同的
Math 92 Writing 84 =if(B1>=80 && B2>=60,"Pass","Fail") // 类似三元表达式 =create(Math,Writing,Result) // 创建一个序列 >A4.insert(0,B1,B2,A3) // 在A4中插入一条数据 //SPL code from有些函数中,会有一些“成对”出现的参数,这两个参数紧密关联或共同起作用。在这样的情况下,它们之间往往用冒号:分隔
Math 92 Writing 84 =if(B1+B2>=180:"A",between(B1+B2,150:180):"B", B1+B2>=120:"C",B1+B2<120:"D") // 条件:成立时的值 =create(Math,Writing,Rank) // 创建一个序列 >A4.insert(0,A3:Rank,B1:Math,B2:Writing) // 在A4中插入一条数据 //SPL code from在有些函数中,可以对某些参数添加一个指示性参数,从而改变与之相关的计算方式,此时也经常用逗号分隔
=demo.query("select * from CITIES") =A1.sort(STATEID,NAME) // 为先按州代码排,同一州的城市再按名称排序 =A1.sort(STATEID,-NAME) // 负号是按名称倒排 //SPL code from函数中的参数,可以按功能明显划分为不同的部分,各个部分之间往往用分号;分隔
=demo.query("select * from CITIES") =A1.groups(STATEID; sum(POPULATION):Population) // 分号前的参数用来分组,分号后的参数用来计算汇总值,汇总值的参数,还用到了冒号分隔符,用来定义汇总字段的名称 =A2.top(-5;Population) // 定义了取前几位的记录 //SPL code from有的函数中,用到的参数很长,而这些参数往往会分成几组,组之间也用分号分隔:
=demo.query("select * from STATES") =demo.query("select EID, NAME, STATE, DEPT, SALARY from EMPLOYEE") =A2.groups(DEPT;count(~):Count) =A2.switch(STATE,A1:NAME; DEPT,A3:DEPT) //SPL code from
函数参数的省略
前方是冒号分隔符的参数,一般是用来对另一个参数的计算模式等补充说明的,如果使用缺省模式,可以省略参数不写
Math 92 Writing 84 =if(B1>=80 && B2>=60,"Pass","Fail") =create(Math,Writing,Result) >A4.insert(0,A3:Result,B1:Math,B2:Writing) >A4.insert(0,B1,B2,A3) // 上面冒号后的字段本来就是默认的,可以省略 //SPL code from用分号分隔的参数,如果分号后方再没有参数,则对应的分号也不必写
[a,b,c,d,e,f,g] =A1.to(4,) // 相当于=A1.to(4,A1.len()) =A1.to(,4) // 相当于=A1.to(1,4) //SPL code from
选项
同一个函数可以有不同的工作方式。函数选项的基本格式是f@o(…),o就是函数f的选项
2004-5-5 2014-7-7
=interval(A1,B1) // 计算两个日期的间隔天数
=interval@y(A1,B1) // 计算两个日期的间隔年数
=interval@m(A1,B1) // 计算两个日期的间隔月数
//SPL code from
常用选项
@a选项,返回所有满足条件的结果
- 用在定位函数中表示返回全部,如A.pos(), A.select(), A.pmax(), A.pselect(), A.minp(), P.align()等
- 而用在写文件函数f.write()或f.export()中时,表示追加
@1选项后,只会返回找到的第1个结果
[1,2,3,4,3,2,1,2,3,2,1] =A1.pos(2) =A1.pos@a(2) =A1.pselect(~==1) =A1.pselect@a(~==1) //SPL code from@z选项,逆序,在一些与顺序有关的排序、定位、选出等函数中,经常使用@z选项,如A.rank(), A.sort(), A.pos(), A.pselect(), A.select()等
@b选项,二分查找 ----- 在一些定位、选出等函数中,经常使用@b选项,如A.pos(), A.pselect(), A.select()等。
- 使用@b选项时,会在查找时使用二分法,二分法具有更高的查找效率,但是要求A必须是有序的,否则有可能获得错误的结果
- 当在文件读写函数中用到@b,就是另外的情况了,如f.import(), f.export(), f.cursor()等。此时,说明读入或写出的是二进制文件。在集算器中,二进制文件称为集文件,扩展名通常为btx,它的存储空间更小,读写速度更快,使用集文件更有效率
同时使用多个函数选项
在需要时,可以同时使用多个允许共用的选项,选项之间没有次序
[1,2,3,4,3,2,1,2,3,2,1]
=A1.pos@az(2)
=A1.pos@za(2)
=demo.query("select * from CITIES")
=A4.select@1z(STATEID:5)
//SPL code from
流程控制
条件
if...else if ... else...
可以写成行
-14 if A1>=0 >B3=A1 else >B3=-A1 //SPL code from也可写成列(块)
-14 if A1>=0 >C3=A1 else >C3=-A1
函数 if(x,a,b) --- 当x成立时,计算表达式a并返回结果,否则计算表达式b并返回结果
循环
无条件循环,通过break跳出
=connect("demo") =A1.query("select * from EMPLOYEE") [] >A1.close() for =A2(A4) if B4.STATE=="Texas" >B2=B2|B4 if B2.len()==10 break //SPL code from- A2执行无条件循环
- 在B2中根据A2中的循环次数,每次获得一条员工记录。在后面的代码中,将Texas州的员工信息保存在B2中,当获取到前10名Texas州的员工资料后,在C6中用break语句跳出循环。
- 使用break语句时,也可以用break C命令,跳出以C为主格的循环体。
for 单元格
=demo.query("select * from EMPLOYEE") 0 =A1.select(STATE=="Texas") for A2 =age(A3.BIRTHDAY) >B1=max(B1,B3) //SPL code fromA2中选出了所有在Texas的员工。
A3执行循环,循环每一位Texas员工,在循环时,计算出每位员工的年龄,并在B1中存储最大年龄。
循环完毕时,就可以在B1中获得所有Texas员工的最大年龄
对于比较简单的循环语句,有时候,可以用序列的循环函数来实现
=demo.query("select * from EMPLOYEE") =A1.select(STATE=="Texas") =A2.max(age(BIRTHDAY)) //SPL code from
for n --- 语句for n也可以看做for to(1,n)的简写。即从1开始,一直循环到n
1000 800 0.1 for 10 >A1=A1/2 >C1=C1*2 if B1>A1 =B1 >B1=A1 >A1=C3 //SPL code fromfor a,b,s --- 从a到b执行循环,每次步进为s,即循环数列to(a,b).step(s)中的各个成员,s缺省时计为1
for 1,100,2 >A2=A2+A1 //SPL code fromfor x ---- 当x为真时循环,主格的值为x计算值。
=demo.query("select * from EMPLOYEE") [] for B1.len()<10 =A1(#A2) if B2.STATE=="Texas" >B1=B1|B2 //SPL code from- 使用了#C来获得当前的循环次数,#C中,C为循环体的主格
嵌套
[] for 2,1000 for A1 if A2%B2==0 next A2 >A1=A1|A2 //SPL code from- 使用next命令时,也可以不指定主格C,跳过next命令格所在的最内层次的循环。
数据
文本数据
txt文件
文件数据
EID NAME SURNAME GENDER STATE BIRTHDAY HIREDATE DEPT SALARY
1 Rebecca Moore F California 1984-09-28 2015-01-18 R&D 7000
2 Ashley Wilson F New York 1990-05-28 2018-01-23 Finance 11000
3 Rachel Johnson F Mexico 1980-10-25 2020-10-09 Sales 9000
4 Emily Smith F Texas 1995-01-14 2016-06-23 HR 7000
5 Ashley Smith F Texas 1985-03-21 2014-06-08 R&D 16000
6 Matthew Johnson M California 1994-05-16 2015-05-16 Sales 11000
7 Alexis Smith F Illinois 1982-06-25 2012-06-24 Sales 9000
8 Megan Wilson F California 1989-02-25 2014-02-26 Marketing 11000
9 Victoria Davis F Texas 1993-10-15 2019-10-16 HR 3000
测试
=file("D:\\Desktop\\test-spl.txt")
=A1.import@t()
//SPL code from
- @t选项,读入数据时,会将这个文本文件的第一行设置为序表的列名
数据库
=connect("demo")
=A1.query("select * from CITIES")
>A1.close()
//SPL code from
用connect函数连接,此时数据读取后,应该用close将数据库连接关闭
其中demo是集算器自带的数据源,可以执行安装目录下的esProc\bin\startDataBase.bat启动。数据源连接后,就可以直接访问数据库
JDBC
集算器JDBC包含两个基础jar包,都位于[安装目录]\esProc\lib目录下:
esproc-bin-xxxx.jar 集算器计算引擎及JDBC驱动包
icu4j_60.3.jar 处理国际化
如果在集算器JDBC需要其它数据库作为集算器中的数据源,那么还需要相应数据库的驱动jar包,比如,使用demo数据库需要hsqldb-2.7.3-jdk8.jar。需要注意的是,集算器JDBC需要JDK1.8或以上版本。
