PS:文章整理的知识内容及资料均来自极客时间《SQL必知必会》专栏
SQL函数以及使用带来的问题
日期函数 EXTRACT: EXTRACT(YEAR FROM '2019-09-04') = YEAR('2019-09-4');
补充:在WHERE子句中使用SQL函数会使索引失效
聚集函数的使用
注意:ORDER BY是对记录进行排序。如果在前面用到了GROUP BY,实际上是一种分组的聚合方式,已经把一组的数据聚合成为了一条记录,所以再进行排序的时候,也相当于是对分的组进行排序
子查询的使用
player球员表为例:
- 非关联子查询:子查询从数据表中查询了数据结果,且这个数据结果只执行一次,然后以这个数据结果作为主查询的条件进行过滤;
例子: SELECT player_name, height FROM player WHERE height = (SELECT max(height) FROM player)
- 关联子查询:子查询的执行依赖于外部查询,子查询中的表用到了外部的表并进行了条件关联,每执行一次外部查询,子查询都要重新计算一次;
例子:
SELECT player_name, height, team_id FROM player AS a
WHERE height > (SELECT avg(height) FROM player AS b WHERE a.team_id = b.team_id)
- ANY(SOME)的使用:查询player表中的球员身高比team_id=1002的任一球员身高高的球员数据
例子:
SELECT player_id, player_name, height FROM player
WHERE height > ANY (SELECT height FROM player WHERE team_id = 1002)
- ALL的使用:查询比team_id=1002的所有球员身高都高的球员数据
例子:
SELECT player_id, player_name, height FROM player
WHERE height > ALL (SELECT height FROM player WHERE team_id = 1002)
- EXIST和IN的查询效率比较
当查询字段字段进行了索引时,主表A数据大于从表B数据,使用IN子查询效率较高,相反则使用EXIST效率较高,因为IN表是外边和内表进行hash连接,是先执行子查询。EXISTS是对外表进行循环,然后在内表进行查询。因此如果外表数据量大,则用IN,如果外表数据量小,则用EXISTS。IN有一个缺陷是不能判断NULL,因此如果字段存在NULL值,则会出现返回,因此最好使用NOT EXISTS。
例如如:
SELECT * FROM A WHERE cc IN (SELECT cc FROM B)
SELECT * FROM A WHERE EXIST (SELECT cc FROM B WHERE B.cc=A.cc)
当A小于B时,用EXIST。因为EXIST的实现,相当于外表循环,实现的逻辑类似于:
for i in A
for j in B
if j.cc == i.cc then ...
当B小于A时,用IN,因为实现的逻辑类似于:
for i in B
for j in A
if j.cc == i.cc then ...
所以哪个表小就用哪个表来驱动,A表小 就用EXIST,B表小 就用IN;
连接的使用
- 交叉连接(笛卡尔积):CROSS JOIN
例子: SELECT * FROM player CROSS JOIN team
- 自然连接:NATURAL JOIN
例子:SELECT player_id, team_id, player_name, height, team_name FROM player NATURAL JOIN team
- 左外连接:LEFT JOIN
例子:SELECT * FROM player LEFT JOIN team ON player.team_id = team.team_id
- 右外连接:RIGHT JOIN
例子:SELECT * FROM player RIGHT JOIN team ON player.team_id = team.team_id
- 自连接:JOIN
例子:SELECT b.player_name, b.height FROM player AS a JOIN player AS b
ON a.player_name = '布雷克-格里芬' AND a.height < b.height
使用连接的注意事项
1、控制连接表的数量
多表连接就相当于嵌套 for 循环一样,非常消耗资源,会让 SQL 查询性能下降得很严重,因此不要连接不必要的表。在许多 DBMS 中,也都会有最大连接表的限制。2、连接时使用WHERE语句过滤
多表连接的时候不要忘记了 WHERE语句,这样可以过滤掉不必要的数据行返回。3、使用自连接代替子查询
在自连接例子中,其实也可以使用子查询。一般情况建议使用自连接,因为在许多 DBMS 的处理过程中,对于自连接的处理速度要比子查询快得多。因为子查询实际上是通过未知表进行查询后的条件判断,而自连接是通过已知的自身数据表进行条件判断,因此在大部分 DBMS 中都对自连接处理进行了优化。
视图
我们需要了解到视图是虚拟表,本身不存储数据,如果想要通过视图对底层数据表的数据进行修改也会受到很多限制,通常我们是把视图用于查询,也就是对 SQL 查询的一种封装。
- 安全性:虚拟表是基于底层数据表的,我们在使用视图时,一般不会轻易通过视图对底层数据进行修改,即使是使用单表的视图,也会受到限制,比如计算字段,类型转换等是无法通过视图来对底层数据进行修改的,这也在一定程度上保证了数据表的数据安全性。同时,我们还可以针对不同用户开放不同的数据查询权限,比如人员薪酬是个敏感的字段,那么只给某个级别以上的人员开放,其他人的查询视图中则不提供这个字段。
- 简单清晰:视图是对 SQL 查询的封装,它可以将原本复杂的 SQL 查询简化,在编写好查询之后,我们就可以直接重用它而不必要知道基本的查询细节。同时我们还可以在视图之上再嵌套视图。这样就好比我们在进行模块化编程一样,不仅结构清晰,还提升了代码的复用率。
存储过程
游标