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 ...
随机推荐
- from __future__ import unicode_literals, absolute_import
Q:python模块中的相对导入,绝对导入,有些地方会写 from __future__ import absolute_import 希望有个更详细的讲解. A: 相对导入:在不指明 package ...
- APUE 学习笔记(十) 高级I/O
1. Unix IPC(InterProcess Communication) 同一主机的各个进程间的IPC:管道.FIFO.消息队列.信号量.共享存储器 不同主机上的各个进程间IPC:socket套 ...
- HDU 4749: Parade Show
看大神代码,发现上交大神很棒的一个思路 题意: 在源数字串中找出尽量多的连续子串,要求子串任意两值的大小关系与目标串相同位置的值的大小关系相同.求源串能拿出的子串的最大数量. 关键词: RK-Hash ...
- hdu 1195(搜索)
Open the Lock Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Tot ...
- LeetCode OJ--Unique Paths *
https://oj.leetcode.com/problems/unique-paths/ 首先,转换成一个排列组合问题,计算组合数C(m+n-2) (m-1),请自动想象成上下标. class S ...
- Xcode 如何计算整个项目的代码行数
参考链接:https://www.cnblogs.com/sunfuyou/p/7921538.html 1.打开终端 2.cd 空格 将工程的文件夹拖到终端上,回车,此时进入到工程的路径 此时已经进 ...
- TCP server和client
http://blog.csdn.net/hguisu/article/details/7445768/ 原文:http://www.cnblogs.com/dolphinX/p/3460545.ht ...
- k8s之存储卷及pvc
1.存储卷概述 因为pod是有生命周期的,pod一重启,里面的数据就没了,所以我们需要数据持久化存储,在k8s中,存储卷不属于容器,而是属于pod,也就是说同一个pod中的容器可以共享一个存储卷,存储 ...
- luogu P2894 [USACO08FEB]酒店Hotel
题目描述 The cows are journeying north to Thunder Bay in Canada to gain cultural enrichment and enjoy a ...
- U-boot for Tiny4412
我的开发板型号: Tiny4412ADK + S700 4GB Flash 1. Build uboot a) 安装好toolchain (arm-linux-gcc-4.5.1-v6-vfp-201 ...