分类: 敏捷开发
2020-10-21 14:30:05
因为支持文件计算、性能优化等独特功能,esProc的SQL功能深受大家喜爱,为了大家更方便地使用,下面将总结SQL的各类应用方案。
SQL的基本数据源为文本文件和Excel。文本文件有两种常见的分隔符,制表符分隔的文件一般以txt为扩展名,逗号分隔的文件通常以csv为扩展名,esProc可凭借扩展名自动识别。Excel有两种不同的版本,格式较旧的xls文件和格式较新的xlsx文件,esProc同样可凭扩展名自动识别。
SQL的基本数据格式为带列名的二维表,比如下面的sales.txt:
OrderID Client SellerId Amount OrderDate 26 TAS 1 2142.4 2009-08-05 33 DSGC 1 613.2 2009-08-14 84 GC 1 88.5 2009-10-16 … |
SQL的基本运行环境为网格脚本,在windows/linux下均可使用。在网格脚本中,可以编写/维护/执行多个SQL,且点击不同的单元格可直接在右边查看计算结果。下面是一些例子:
具体SQL写法不是本文重点,若感兴趣可参考 [在文件上使用 SQL 查询的示例]()
不方便使用图形环境时,可以在命令行执行SQL。Windows下应使用esprocx.exe命令,例如:
esprocx.exe -r select * from Order.txt |
需要注意的是,SQL在 IDE中必须使用前导符号$,而命令行中可以省略该符号。
Linux环境下应使用esprocx.sh 命令,例如:
./esprocx.sh -r select * from Order.txt |
有些文件没有列名(列标题),则可以将SPL语句嵌入SQL,利用SPL的能力灵活处理列名。比如sOrderNT.txt部分数据如下:
26 TAS 1 2142.4 2009-08-05 33 DSGC 1 613.2 2009-08-14 84 GC 1 88.5 2009-10-16 133 HU 1 1419.8 2010-12-12 |
按第2列查询时,SQL应写作:
$select * from {file("sOrderNT.txt").import()} where _2='TAS' |
从SQL中可以看到,数据无列名时,则以"下划线+序号"为默认列名,第2列的列名就用_2表示,其他列以此类推。{}内是SPL语言,其中import函数可以读取格式更复杂的文件,详细用法参考
为了更直观地使用列名,可以先改列名再计算。传统的SQL写法是用子查询改列名,上面的SQL可改为:
$select * from ( select _1 OrderID ,_2 Client, _3 SellerId, _4 Amount, _5 OrderDate from {file("sOrderNT.txt").import()}) where Client='TAS' |
传统的子查询效率不高且阅读不便,使用SPL语句可以避免子查询,同时可以达到修改列名的目的:
$select * from {file("sOrderNT.txt").import().rename(_1:OrderID, _2:Client, _3:SellerId, _4:Amount, _5:OrderDate)} where Client='TAS' |
有些文件的分隔符不是常见的制表符或逗号,而是分号冒号等特殊符号,有时甚至用多个字符当分隔符,这种情况下应该用SPL语句中的import函数来指定分隔符。
比如sep.txt的分隔符是双线||,则可以用下面的SQL来读取:
$select * from {file("sep.txt").import@t(;,"||")} |
|
有些文件没有用回车换行区分记录,而是用其他符号,这样的文件整体呈现为一个大字符串。比如SOrderNL.txt的记录之间用|符号分隔:
OrderID Client SellerId Amount OrderDate|26 TAS 1 2142.4 2009-08-05|33 DSGC 1 613.2 2009-08-14… |
这种情况要把文件读为字符串,将|替换成回车换行,再用import函数解析为二维表。
$select * from {replace(file("sOrderNL.txt").read(),"|","\r\n").import@t()} |
read函数可参考
有些文件存在空行,需要跳过才能使用。处理这种情况的一般思路是:在SQL中嵌入SPL语句,用SPL语句读入文件,查询出有用的数据行。
最简单的情况是首行数据有效(可以用import函数解析成二维表),而首行之后不定的位置存在空行。这样文件可用以下SQL查询:
$select * from {file("sOrderb.txt").import@t().select(#1)} |
代码中第二个select是SPL的查询函数,select(#1)表示第1个字段不为空。可以用该函数筛选更复杂的数据行,而不仅仅是空行。函数select参考
如果首行数据无效,就不能用import函数解析成二维表了,这种情况下要用read函数读成行数据,找到有效数据后,再转为二维表。比如前3行无效,正式数据从第4行开始,SQL代码为:
$select * from {file("sOrderb.txt").read@n().to(4:).concat("\r\n").import@t()} |
代码中to(4:)表示取第4行直到结尾,即有效数据。concat("\r\n")表示将多行数据拼成一个大字符串,行之间用回车换行符连接。Import函数可将字符串转为二维表。
更复杂的情况下,文件在任意位置都可能存在空行,这时要用SPL的select函数进行一般查询,代码如下:
$select * from {file("sOrderb.txt").read@n().select(~!="").concat("\r\n").import@t()} where Client='TAS' |
从前面例子可以看出,有些文件不够规范,需要用较长的SPL代码去解析文件。SPL代码太长,就无法利用网格代码的优势,不仅影响阅读代码,且不方便查错改错。为了充分利用网格代码的优势,esProc SQL允许将任意的SPL中间计算结果作为数据源。
比如“文件在任意位置都可能存在空行”这个例子,可以改用下面的代码:
|
A | B |
1 | =file("sOrderb.txt").read@n() | /按行读入文件 |
2 | =A1.select(~!="") | /取非空行 |
3 | =A2.concat("\r\n").import@t() | /合并为大字符串,解析为二维表 |
4 | $select * from {A3} where Client='TAS' | /以SPL为源执行SQL |
任意的SPL中间结果都可以作为SQL的数据源,这就给SQL语句提供了无限的可能性,包括复杂的文件解析、特殊数据源、大文件计算、循环判断、多源混算等等。
把Excel文件当数据源是SQL 的基本用法,也可以利用SPL,把Excel粘贴而来的数据当做数据源。
比如Excel存储着学生成绩,如下图:
|
A | B | C | D |
1 | name | math | english | physics |
2 | lily | 97 | 100 | 99 |
3 | Joshua | 100 | 99 | 100 |
4 | Sarah | 98 | 99 | 96 |
5 | Bertram | 94 | 95 | 85 |
6 | Paula | 91 | 88 | 91 |
7 | Sophia | 92 | 81 | 76 |
8 | Ben | 87 | 80 | 76 |
9 | Ruth | 92 | 91 | 87 |
10 | Pag | 95 | 87 | 87 |
首先在Excel中选定A1:D10,连带列名一起复制粘贴到esProc脚本的A1单元格,再编写SPL代码,最后编写SQL。如下图:
|
A | B |
1 | name math english physics lily 97 100 99 Joshua 100 99 100… | /从Excel粘贴来的数据 |
2 | =A1.import@t() | /解析为二维表 |
3 | $select * from {A2} where math>=80 | /执行SQL |
注意,一定要进入A1格的编辑状态才能进行复制,不然会把剪贴板的内容填进一大片格子,虽然也有办法进行计算,但占有区域太大,会影响代码布局。
多行记录属于格式不规范的文件,比如下面的文件每三行代表一条记录,第一条记录是:26\TAS\1\2142.4\2009-08-05。
26 TAS 1 2142.4 2009-08-05 33 DSGC 1 613.2 2009-08-14 84 GC 1 88.5 2009-10-16 |
下面使用SPL将该文件整理成规范二维表,再用作SQL数据源,代码如下:
|
A | B |
1 | =file("D:\\data.txt").import@si() | 将文件读为序列,不拆分字段 |
2 | =A1.group((#-1)\3) | 每3行分一组 |
3 | =A2.new(~(1):OrderID, (line=~(2).array("\t"))(1):Client,line(2):SellerId,line(3):Amount,~(3):OrderDate ) | 创建二维表,~(1)表示当前组的第1个成员 |
4 | $select * from {A3} where year(OrderData)=2009 |
|
利用SPL语言,可以在SQL中实现不同数据源之间的混合计算。
比如Oracle的sales表存放员工的销售订单,excel文件emp.xlsx存放各部门的员工信息,需要计算每个部门的销售额,可使用如下代码:
|
A | B |
1 | =file("emp.xlsx").xlsimport@t() | /Excel 数据源 |
2 | =connect("orcl").query@x("select * from sales") | /数据库数据源 |
3 | $select e.dept,sum(s.amount) from {A2} s left join {A1} e on s.sellerid=e.eid group by e.dept | /混合计算 |
如果文件较大,SQL性能较差,可转为esProc高性能文件格式btx。比如将orders.txt转为orders.btx,代码如下:
|
A | B |
1 | =file("orders.txt").cursor@t() | /游标方式打开大文本文件 |
2 | =A1.sortx(OrderID) | /排序 |
2 | =file("sales.btx").export@z(A2) | /转为btx格式,@z表示文件有序 |
btx的基本用法与文本文件和Excel一样,但性能会显著提升,比如条件查询:
$select orderid,client,amount from sales.btx where Client='TAS' |