跳至主要內容

SPL的基本使用

程序员李某某大约 15 分钟

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>

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()将字符串或者长整数转换为日期,时间或者日期时间类型。

  • 排号:不理解(官方说明open in new window

集算器中,布尔型、字符串及日期时间数据,都会靠左对齐,显示为黑色。

数据类型的判断

  • 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 from	
    
    • A2中选出了所有在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 from		
    
  • for a,b,s --- 从a到b执行循环,每次步进为s,即循环数列to(a,b).step(s)中的各个成员,s缺省时计为1

    for 1,100,2	>A2=A2+A1	
    //SPL code from 
    
  • for 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或以上版本。

上次编辑于:
贡献者: 李元昊