SQL还有多少"理所当然";还有那些"就是这样"
前言废话——sql是程序员的饭碗,繁琐but万能,但能干并不意味着适合干,每当多表关联寻找外键时,我都在经历一种没有选择的痛苦。sql不完美,但长期代码让人无暇顾及完美,再痛苦的呐喊到最后都归于疲倦已极的无奈,就在还愿意记下它们的时候存个档吧。午饭吃饱了,打个盹,做个梦去。
正文:
发明SQL的主要目的是为结构化数据提供一种屏弊数据物理存储方案的访问方法,因此SQL中大量使用了类英语的词汇和语法以降低理解和书写困难。作为SQL基础理论的关系代数是个完备的计算体系,原则上可以计算一切。这样看来,我们理所应当地用SQL完成各种数据计算需求。
但是,尽管关系数据库取得了巨大的成功,SQL却显然没有达到其发明初衷,除了极少数简单的查询可由终端用户采用SQL完成外,绝大多数的SQL使用者仍是技术人员,甚至许多复杂的查询对技术人员也不是件容易的事。
通过一个很简单的例子来考察SQL在计算方面的缺点。
假设有一个由三个字段构成的销售业绩表sales_amount(为了简化问题,省去日期信息):
Sales 销售员姓名,假定无重名
Product 销售的产品
Amount 该销售员在该产品上的销售额
现在我们想知道空调和电视销售额都在前10名的销售员名单。这个问题很简单,人们会很自然地设计出如下计算过程:a、先按空调销售额排序,找出前10名;b、再按电视销售额排序,找出前10名;c、对a、b的结果取交集。
用SQL做:
a、找出空调销售额前10名,这很简单:
select top 10 sales from sales_amount where product='AC' order by amount desc
b、找出电视销售额前10名,动作一样:
select top 10 sales from sales_amount where product='TV' order by amount desc
c、求1、2的交集。这有点麻烦,因为SQL不支持步骤化、上两步的计算结果无法保存,所以只能重抄一遍:
select * from
( select top 10 sales from sales_amount where product='AC' order by amount desc )
intersect
( select top 10 sales from sales_amount where product='TV' order by amount desc )
一个只3步的简单计算得用SQL写成这样,而日常计算多达10几步的比比皆是,这显然超出来许多人的可接受能力。
这样,我们知道SQL的第一个重要缺点:不支持步骤化。把复杂的计算分步可以在很大程度地降低问题的难度,反过来,把多步计算汇成一步则很大程度地提高了问题的难度。
如果老师要求小学生做应用题时只能列一个算式完成,小朋友们会多么苦恼(当然,不乏一些聪明孩子搞得定)。
SQL查询不能分步,但用SQL写出的存储过程可以分步,那么用存储过程是否可以方便地解决这个问题呢?
不提使用存储过程的技术环境有多复杂(这足以令大多数人却步了)和数据库的差异性造成的不兼容,我们只从理论上来看用分步SQL是否能让这个计算更简捷些。
a、计算空调销售额前10名。语句还是那样,但我们需要把结果存起来供第3步用,而SQL中只能用表存储集合数据,这样我们要建一个临时表:
create temporary table x1 as
select top 10 sales from sales_amount where product='AC' order by amount desc
b、计算电视销售额前10名。类似地:
create temporary table x2 as
select top 10 sales from sales_amount where product='TV' order by amount desc
c、求交集,前面麻烦了,这步就简单些:
select * from x1 intersect x2
分步后思路变清晰了,但临时表的使用仍显繁琐。在以批量结构化数据计算中,作为中间结果的临时集合是相当普遍的,如果都建立临时表来存储,不仅运算效率低,同时也不直观。
而且,SQL不允许某个字段取值是集合(即临时表),这样,有些计算即使容忍了繁琐也做不到。
如果我们把问题改为计算所有产品销售额都在前10名的销售员,试想一下应当如何计算,继续延用上述的思路很容易想到:
1. 将数据按产品分组,将每组排序,取出前10名;
2. 将所有的前10名取交集;
由于我们事先不知道会有多个产品,这样需要把分组结果也存储在一个临时表中,而这个表有个字段要存储对应的分组成员,这是SQL不支持的,办法就行不通了。
如果有窗口函数(SQL2003标准)的支持,可以转换思路,按产品分组后,计算每个销售员在所有分组的前10名中出现的次数,若与产品总数相同,则表示该销售员在所有产品销售额中均前在前10名内。
select sales
from ( select sales,
from ( select sales,
rank() over (partition by product order by amount desc ) ranking
from sales_amount)
where ranking <=10 )
group by sales
having count(*)=(select count(distinct product) from sales_amount)
这样的SQL,有多少人会写呢?
况且,窗口函数在许多数据库中还不支持。那么,就只能用存储过程写循环依次计算每个产品的前10名,与上一次结果做交集。这个过程比用高级语言编写程序并不简单多少,而且仍然要面向临时表的繁琐。
现在,我们知道了SQL的第二个重要缺点:集合化不彻底。虽然SQL有集合概念,但并未把集合作为一种基础数据类型提供,这使得大量集合运算在思维和书写时都需要转换翻译。
SQL还有多少"理所当然";还有那些"就是这样"的更多相关文章
- mybatis中#{}与${}的差别(如何防止sql注入)
默认情况下,使用#{}语法,MyBatis会产生PreparedStatement语句中,并且安全的设置PreparedStatement参数,这个过程中MyBatis会进行必要的安全检查和转义. # ...
- 转!! PreparedStatement是如何防止SQL注入的
SQL注入最简单也是最常见的例子就是用户登陆这一模块,如果用户对SQL有一定的了解,同时系统并没有做防止SQL注入处理,用户可以在输入的时候加上'两个冒号作为特殊字符,这样的话会让计算机认为他输入的是 ...
- MyBatis怎么防止SQL注入
SQL注入是一种代码注入技术,用于攻击数据驱动的应用,恶意的SQL语句被插入到执行的实体字段中(例如,为了转储数据库内容给攻击者).[摘自] SQL injection - Wikipedia SQL ...
- java持久层框架mybatis如何防止sql注入
看到一篇很好的文章:http://www.jfox.info/ava-persistence-framework-mybatis-how-to-prevent-sql-injection sql注入大 ...
- 误报的java.sql.SQLException: Parameter number 21 is not an OUT parameter
今天为了模拟一个mysql内存不释放问题,要测试一个存储过程,同时具有出参和入参,启动时报了上述错误. <select id="funcl_trd_secu_execution_que ...
- SQL语句执行顺寻
SQL语句执行的时候是有一定顺序的.理解这个顺序对SQL的使用和学习有很大的帮助. 1.from 先选择一个表,或者说源头,构成一个结果集. 2.where 然后用where对结果集进行筛选.筛选出需 ...
- SQL Server Profiler监控SQL Server性能
全面掌握SQL Server Profiler 1. 原理与相关概念介绍 SQL Server Profiler,大家已经非常熟悉.常常在性能优化中使用,本文档详细介绍SQL Server ...
- MyBatis如何防止SQL注入
转自:http://www.myexception.cn/sql/1938757.html SQL注入是一种代码注入技术,用于攻击数据驱动的应用,恶意的SQL语句被插入到执行的实体字段中(例如,为了转 ...
- mybatis防止sql注入
SQL注入是一种代码注入技术,用于攻击数据驱动的应用,恶意的SQL语句被插入到执行的实体字段中(例如,为了转储数据库内容给攻击者).[摘自] SQL injection - Wikipedi ...
随机推荐
- python解析yaml文件
YAML语法规则: http://www.ibm.com/developerworks/cn/xml/x-cn-yamlintro/ 下载PyYAML: http://www.yaml.org/ 解压 ...
- 【CF721C】Journey(拓扑排序,最短路,DP)
题意:给一个无环的图,问用不超过T的时间从1到n最多可以经过多少个点.要求输出一条路径. 思路:因为无环,可以用DP做.不过因为时间最短的原因要拓扑排序后再DP,目测由底向上的更新也是可以的. ; . ...
- 防止点击asp.net的button按钮刷新页面(保留button的外观)
原文发布时间为:2008-08-06 -- 来源于本人的百度文章 [由搬家工具导入] Button btn=new Button(); 1、如果用 btn.Enabled=false;是可以防止刷新的 ...
- luogu 1142 轰炸 最多共线点数
题目链接 题意 给定\(n(n\leq 700)\)个点,问共线的点最多有多少个? 思路 \(O(n^3)\):枚举两个顶点确定一条直线,再看有多少个顶点在这条直线上.讲道理会T. \(O(n^2lo ...
- Linux 之 LNMP服务器搭建-PHP
LNMP服务器搭建-PHP 参考教程:[千峰教育] 安装: (1)解压源码包 cd /lnmp/srctar -jxvf php-7.3.2.tar.bz2cd php-7.3.2 (2)配置选项 . ...
- ExcelHelper类
/// <summary> /// ExcelHelper类 /// </summary> using System; using System.IO; using Syste ...
- hdu3947 给一些已知(需费用)路径去覆盖一些边 //预先加灌法费用流
River Problem 题意:一个有向树(河流),只有一个汇点1,每条边只有一个出度.有些河道有污染指数xi,必需要治理,有m段路径,可以去覆盖这些,每被覆盖一次,xi降低响应值. :即 给出一些 ...
- AC日记——[HAOI2015]树上操作 洛谷 P3178
题目描述 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a .操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 ...
- 解决 ecshop 搜索特殊字符关键字(如:*,+,/)导致搜索结果乱码问题
病症:ecshop系统搜索会对搜索关键字进行分词,然后对关键字分词进行正则匹配,并且标红加粗处理,如果关键字分词有特殊字符,则正则匹配结果会导致乱码 解决方法: 1.找到特殊字符串数组:$ts_str ...
- 总结 Eclipse 编程常用的快捷键
Eclipse 常用快捷键Eclipse的编辑功能非常强大,掌握了Eclipse快捷键功能,能够大大提高开发效率.Eclipse中有如下一些和编辑相关的快捷键. 1. [ALT+/] 此快捷键为用户编 ...