德阳做网站,网站开发说明文档,网站内部链接导向,建筑施工图纸培训班现代应用开发中#xff0c;通常只用SQL实现简单的数据存取动作#xff0c;而主要的计算过程和业务逻辑直接在应用程序中实现#xff0c;主要原因在于#xff1a;
过于复杂的SQL很难调试、编写、阅读、修改。SQL有方言特征#xff0c;大量使用SQL后#xff0c;会导致程序…现代应用开发中通常只用SQL实现简单的数据存取动作而主要的计算过程和业务逻辑直接在应用程序中实现主要原因在于
过于复杂的SQL很难调试、编写、阅读、修改。SQL有方言特征大量使用SQL后会导致程序很难移植。架构方面要求业务逻辑在应用中实现而不能依赖于数据库否则耦合性过高。有些计算SQL不擅长包括复杂的集合计算、有序计算、关联计算、多步骤计算经常也需要移到数据库外实现。实现流程控制时因为更难移植、耦合性更高、影响数据安全不方便使用存储过程。
此外还有涉及多数据库和非数据库的场景也无法使用SQL完成计算任务只能在外部完成。
这样就要在应用程序中实现SQL后计算任务。
SQL返回的数据一般都是结构化数据那么好的SQL后计算技术也要有方便的结构化数据对象能够进一步计算和处理返回的数据提供丰富的库函数拥有不亚于SQL的计算能力最好还能支持循环和判断语法以实现流程控制。特别地SQL后计算技术要用在应用程序中要易于被集成。
Java是重要的开发语言但JDK提供的方法过于基础虽然能实现SQL后计算但开发效率很低。
ORM是Java中用来实现SQL后计算的常见方案。但几种较流行的ORM都缺乏专业的结构化数据对象不支持动态数据结构。虽然可以利用Java实现流程控制但难以进行灵活的计算。这些ORM技术的计算能力还远不如SQL提供的计算函数非常有限用Java硬写的现象仍然非常普遍。
Stream的链式编程比ORM的HQL更加面向对象且有Lambda语法的加成也常被用于SQL后计算有些ORM还能直接生成Stream对象。但Stream同样没有专业的结构化数据对象不支持动态数据结构。此外Stream的计算能力也较差甚至不如ORM即使排序、分组汇总、关联这样的基础计算也要辅以大量编码。
Kotlin基于JVM且在链式编程和Lambda语法上对Stream进行了一系列改进也可以用于SQL后计算。但因为编译型语言的底层Kotlin只能对Stream小幅微调重大缺点一个没少。
Python Pandas有较强大的结构化数据处理能力有时也可以用于SQL后计算但因为缺乏易用的接口很难被Java集成很少出现在正式项目中。
esProc SPL是更好的SQL后计算技术。
专业的结构化数据对象
SPL是JVM下的开源结构化数据计算引擎内置专业的结构化数据对象序表可以和数据库表/记录方便地互转支持动态数据结构提供了灵活易用的访问方法、维护方法、计算函数。序表专业性强为数据计算和流程控制提供了有力的底层支撑可以方便地实现SQL后计算中的各类业务逻辑。
直接的数据库交换方法可以在数据库表SQL结果集和SPL序表之间进行互转。
比如使用query函数执行SQL生成单条记录序表 AB1connect(orcl)//连接数据库2.query(select * from sales where orderid?,201)rA1//查询单条记录3db.close()//关闭数据库连接
如果SQL返回多条记录则自动生成多条记录序表
TA1.query(“select * from salesR where SellerID?”,10)
反过来也简单用update函数就可以将序表记录批量地持久化到数据库。比如原序表为T经过多条件记录的增删改之后的序表为NT将两者的变更结果统一写入数据库
A1.update(NT:T,sales;ORDERID)
灵活的序表访问方法可以按字段名或记录号自由地访问序表。
取序表的第3条记录T(3)
取后3条记录:T.m([-1,-2,-3])
取记录的字段值T(3).Amount*0.05
取一列返回集合T.(Amount)
取几列返回集合的集合T.([CLIENT,AMOUNT])
先按字段名取再按记录序号取T.(AMOUNT)(3)
先按记录序号取再按字段名取T(3).AMOUNT
易用的序表维护方法可以对单条或多条记录记录进行统一的增删改操作。
追加记录T.insert(200,“APPL”,10,2400.4,date(“2010-10-10”))
修改记录T(3).Amount T(3). Amount*1.05
删除记录T.delete(T.select(ORDERID209 || ORDERID208))
丰富的序表计算函数可进行完整的SQL式计算。
过滤T.select(Amount1000 Amount3000 like(Client,“bro”))
排序T.sort(-Client,Amount)
去重T.id(Client)
汇总T.max(Amount)
分组汇总后过滤 T.groups(year(OrderDate),Client; avg(Amount):amt).select(amt2000)
关联join(Orders:o,SellerId ; Employees:e,EId).groups(e.Dept; sum(o.Amount))
交集T1.id(Client) ^ T2.id(Client)
TopNT.top(-3;Amount)
分组topNT.groups(Client;top(3,Amount))
支持动态数据结构可根据上一步的计算结果推断出新数据结构并自动生成新序表新序表可直接进行计算。比如先分组汇总再过滤最后排序
T.groups(SellerId, Client; sum(Amount):amt, count(1):cnt).select(amt10000 amt30000 like(Client,“*bro*”)).sort(amt)
使用支持动态数据结构的序表开发者可以更加关注计算本身而不是思考如何事先定义结果集。这样的编码风格不仅简短易懂而且更符合自然思维开发效率可以显著提升。在多步骤的复杂业务逻辑中动态数据结构带来的优势更加明显。
强大的结构化数据计算能力
SPL提供了多种方便易用的语法内置大量功能强大的函数可以简化复杂的有序运算、集合运算、分布计算、关联计算。很多用SQL和存储过程难以表达的计算用SPL都可以轻松实现。
函数选项、层次参数等方便的语法功能相似的函数可以共用一个函数名只用函数选项区分差别比SQL更加灵活方便。比如select函数的基本功能是过滤如果只过滤出符合条件的第1条记录可使用选项1
T.select1(Amount1000)
并行过滤适合数据量较大的情况使用选项m
T.selectm(Amount1000)
二分法排序即对有序数据用二分法进行快速过滤使用b
T.selectb(Amount1000)
有序分组即对分组字段有序的数据将相邻且字段值相同的记录分为一组使用b
T.groupsb(Client;sum(Amount))
函数选项还可以组合搭配比如
Orders.select1b(Amount1000)
结构化运算函数的参数有些很复杂比如SQL就需要用各种关键字把一条语句的参数分隔成多个组但这会动用很多关键字也使语句结构不统一。SPL使用层次参数简化了复杂参数的表达即通过分号、逗号、冒号自高而低将参数分为三层
join(Orders:o,SellerId ; Employees:e,EId)
内置大量日期函数和字符串函数在数量和功能上远远超过其他技术甚至SQL同样的运算代码量更短。比如
时间类函数日期增减elapse(“2020-02-27”,5) //返回2020-03-03
星期几dayw(“2020-02-27”) //返回5即星期4
N个工作日之后的日期workday(date(“2022-01-01”),25) //返回2022-02-04
字符串类函数判断是否全为数字isdigit(“12345”) //返回true
取子串前面的字符串substrl(“abCDcdef”,“cd”) //返回abCD
按竖线拆成字符串数组“aa|bb|cc”.split(“|”) //返回[“aa”,“bb”,“cc”]
SPL还支持年份增减、求年中第几天、求季度、按正则表达式拆分字符串、拆出SQL的where或select部分、拆出单词、按标记拆HTML等功能。
简化复杂的有序运算。涉及跨行的有序运算通常都有一定的难度比如比上期和同期比。SPL使用字段[相对位置]引用跨行的数据可显著简化代码还可以自动处理数组越界等特殊情况经常比SQL更方便。比如追加一个计算列rate计算每条订单的金额增长率
T.derive(AMOUNT/AMOUNT[-1]-1: rate)
综合运用位置表达式和有序函数很多SQL难以实现的有序运算都可以用SPL轻松解决。比如根据考勤表找出连续 4 周每天均出勤达 7 小时的学生 A1connect(mysql)2A1.queryx(SELECT SID,ATTDATE,DURATION,null AS W FROM STUTEST WHERE DURATION7 ORDER BY SID,ATTDATE).run(Wpdatew(ATTDATE))3A2.groupo(SID;~.groupso(W;count(~):CNT).select(CNT7).groupi(W-W[-1]!7).max(~.len()):weeks)4A3.select(weeks4).(SID)
简化复杂的集合运算SPL序表的集合化更加彻底配合灵活的语法和强大的集合函数可大幅简化复杂的集合计算。比如在各部门找出比本部门平均年龄小的员工 A1…//省略序表Employees的生成过程2Employees.group(DEPT; (a~.avg(age(BIRTHDAY)),~.select(age(BIRTHDAY)a)):YOUNG)3A2.conj(YOUNG)
计算某支股票最长的连续上涨天数 A1…//省略序表AAPL的生成过程2a0,AAPL.max(aif(priceprice[-1],a1,0))
SPL可以方便地实现分步计算序表的集合化更加彻底可以用变量方便地表达集合适合多步骤计算很多SQL难以表达的集合运算用SPL都可以轻松实现。比如找出销售额累计占到一半的前n个大客户并按销售额从大到小排序 AB1//省略取数据的过程 2A1.sort(amount:-1)/销售额逆序排序可在SQL中完成3A2.cumulate(amount)/计算累计序列4A3.m(-1)/2/最后的累计即总额5A3.pselect(~A4)/超过一半的位置6A2(to(A5))/按位置取值
简化复杂的关联计算。序表的专业性体现在多方面其中之一是支持对象引用的形式表达关联开发者可以通过点号直观地访问关联表从而提高开发效率。很多SQL难以表达的关联计算用SPL都可以轻松实现。比如根据员工表计算女经理的男员工
employees.select(gender:“male”,dept.manager.gender:“female”)
灵活的流程控制能力
SPL提供了灵活易用的分支判断语句、循环语句配合专业的结构化数据对象可以方便地实现各类业务逻辑。
分支判断语句 AB2… 3if T.AMOUNT10000T.BONUST.AMOUNT*0.054else if T.AMOUNT5000 T.AMOUNT10000T.BONUST.AMOUNT*0.035else if T.AMOUNT2000 T.AMOUNT5000T.BONUST.AMOUNT*0.02
循环语句 AB1dbconnect(db) 2Tdb.queryx(select * from sales where SellerID? order by OrderDate,9)3for TA3.BONUSA3.BONUSA3.AMOUNT*0.014 A3.CLIENTCONCAT(LEFT(A3.CLIENT,4), co.,ltd.)5 …
与Java的循环类似SPL还可用break关键字跳出中断当前循环体或用next关键字跳过忽略本轮循环不展开说了。
流程控制语句配合序表可以用统一的语法风格实现业务逻辑包括数据库读写、事务处理、流程处理、数据计算。比如根据一定的规则计算奖金 ABC1dbconnecte(dbName) /连接数据库开启事务2db.query1(select sum(Amount) from sales where sellerID? and year(OrderDate)? and month(OrderDate)?, p_SellerID,year(now()),month(now())) /查询当月销售额3if(A210000 :200, A210000 A22000 :100, 0) /本月累计奖金4p_Amount*0.05 /本单固定奖金5BONUSA3A4 /总奖金6create(ORDERID,CLIENT,SELLERID,AMOUNT,BONUS,ORDERDATE) /创建订单的数据结构7A6.record([p_OrderID,p_Client,p_SellerID,p_Amount,BONUS, date(now())]) /生成一条订单记录8db.updateik(A7,sales;ORDERID) /尝试写入库表9db.error() /入库结果10if A90A1.commit()/成功则提交事务11ElseA1.rollback()/失败则回滚事务12db.close() /关闭数据库连接13return A9 /返回入库结果
优化体系结构
SPL支持JDBC接口代码可外置于Java耦合性更低。SPL具有解释执行的特性支持库外计算和代码移植支持跨库跨源计算在SQL后计算中可提供良好的架构性。
SPL提供了易用的JDBC接口可被Java代码无缝集成。比如将前面的SPL代码存为脚本文件再在Java中以存储过程的形式调用文件名 java
Class.forName(com.esproc.jdbc.InternalDriver);
Connection connection DriverManager.getConnection(jdbc:esproc:local://);
Statement statement connection.createStatement();
ResultSet result statement.executeQuery(call writeBonus());SPL代码外置于Java通过文件名被调用既不依赖数据库也不依赖Java业务逻辑和前端代码分离耦合性低。
解释执行和热切换。业务逻辑数量多复杂度高变化是常态。良好的系统构架应该有能力应对变化的业务逻辑。ORM的本质是Java代码需要先编译再执行一般都要停机才能部署应对变化的业务逻辑时非常繁琐。SPL是基于Java的解释型语言无须编译就能执行脚本修改后立即生效支持不停机的热切换适合应对变化的业务逻辑。
方便代码移植。SPL通过数据源名从数据库取数如果需要移植只要改动配置文件中的数据源配置信息而不必修改SPL代码。SPL支持动态数据源可通过参数或宏切换不同的数据库从而进行更方便的移植。为了进一步增强可移植性SPL还提供了与具体数据库无关的标准SQL语法使用sqltranslate函数可将标准SQL转为主流方言SQL仍然通过query函数执行。
方便管理运营。由于支持库外计算代码可被第三方工具管理方便团队协作SPL脚本可以按文件目录进行存放方便灵活管理成本低SPL对数据库的权限要求类似Java不影响数据安全。
跨库和跨源计算。SPL序表可以统一读取各类数据源含RDB可以用统一的代码计算各类数据源可以方便地实现跨库计算。比如对MySQL和Oracle进行内关联 A1mysql1.query(select SellerId, sum(Amount) subtotal from Orders group by SellerId)2orcl.query(select EId,Name from employees)3join(A1:O,SellerId; A2:E,EId).new(O.Name:name, O.Dept:dept, E.subtotal:amt)
SPL支持多种非RDB数据源可进行RDB和非RDB之间的混合计算。包括txt\csv\xls等文件MongoDB、Hadoop、redis、ElasticSearch、Kafka、Cassandra等NoSQL以及WebService XML、Restful Json等多层数据。
ORM以及Stream/Kotlin缺乏专业的结构化数据对象和运算能力Python Pandas难以被Java集成。SPL内置专业的结构化数据对象具有强大的结构化数据计算能力和灵活的流程控制能力可以方便地实现各类业务逻辑。提供了易用的JDBC接口可以被Java方便地集成。还有更多结构性优势包括耦合性低、解释执行和热切换、库外计算以及跨库和跨源计算。
SPL资料
SPL官网SPL下载SPL源代码
欢迎对SPL有兴趣的加小助手VX号SPL-helper进SPL技术交流群