因为支持文件计算、性能优化等独特功能,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 查询的示例](http://c.raqsoft.com.cn/article/1600073770278)
在命令行执行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函数可以读取格式更复杂的文件,详细用法参考http://doc.raqsoft.com/esproc/func/fimport.html
为了更直观地使用列名,可以先改列名再计算。传统的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函数可参考http://doc.raqsoft.com/esproc/func/read.html
跳过空行
有些文件存在空行,需要跳过才能使用。处理这种情况的一般思路是:在SQL中嵌入SPL语句,用SPL语句读入文件,查询出有用的数据行。
最简单的情况是首行数据有效(可以用import函数解析成二维表),而首行之后不定的位置存在空行。这样文件可用以下SQL查询:
$select * from {file("sOrderb.txt").import@t().select(#1)}
代码中第二个select是SPL的查询函数,select(#1)表示第1个字段不为空。可以用该函数筛选更复杂的数据行,而不仅仅是空行。函数select参考http://doc.raqsoft.com/esproc/func/select.html
如果首行数据无效,就不能用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代码去解析文件。SPL代码太长,就无法利用网格代码的优势,不仅影响阅读代码,且不方便查错改错。为了充分利用网格代码的优势,esProc SQL允许将任意的SPL中间计算结果作为数据源。
比如“文件在任意位置都可能存在空行”这个例子,可以改用下面的代码:
任意的SPL中间结果都可以作为SQL的数据源,这就给SQL语句提供了无限的可能性,包括复杂的文件解析、特殊数据源、大文件计算、循环判断、多源混算等等。
数据源为Excel 粘贴而来的数据
把Excel文件当数据源是SQL的基本用法,也可以利用SPL,把Excel粘贴而来的数据当做数据源。
比如Excel存储着学生成绩,如下图:
首先在Excel中选定A1:D10,连带列名一起复制粘贴到esProc脚本的A1单元格,再编写SPL代码,最后编写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数据源,代码如下:
多源混算
利用SPL语言,可以在SQL中实现不同数据源之间的混合计算。
比如Oracle的sales表存放员工的销售订单,excel文件emp.xlsx存放各部门的员工信息,需要计算每个部门的销售额,可使用如下代码:
高性能文件格式
如果文件较大,SQL性能较差,可转为esProc高性能文件格式btx。比如将orders.txt转为orders.btx,代码如下:
btx的基本用法与文本文件和Excel一样,但性能会显著提升,比如条件查询:
$select orderid,client,amount from sales.btx where Client='TAS'
Txt和btx的差异可参考http://doc.raqsoft.com/esproc/tutorial/jiwenjian.html
如果想进一步提高SQL性能,就要使用更高性能的ctx文件以及esProc扩展的SQL+能力了,可以提供包括并行计算等能力,参考:http://doc.raqsoft.com/esproc/func/sqljia.html