一、视图
- 什么是视图?
数据库中储存的是我们所需要的数据,而视图中存放的是sql的查询语句。当我们使用视图的时候,客户端会运行视图中的查询语句并创建一张临时表。但是当数据库和客户端断开连接的时候,这些临时表将不会被保存,保存的是视图中的sql语句。
2. 如何创建视图?
CREATE VIEW 视图名称 (视图列名1,视图列名2,...)
AS
SELECT 查询语句;
/*创建按性别汇总人数的视图*/
CREATE VIEW 按性别汇总(性别,人数) /*视图中列名顺序应与select查询语句中的列名一一对应*/
AS
SELECT 性别,COUNT(*)
FROM student
GROUP BY 性别;
首先在“查询编辑器”输入sql语句,点击“视图”,然后选择“刷新”,新的视图表格将会出现在视图中。当我们想要使用视图的时候,直接在from语句中使用新的视图表格。
3. 视图的作用?
- 可以节省数据库的存储空间。因为视图存放的是sql语句,临时表中数据不需要被存储。
- 数据视图会自动更新。
- sql语句需要频繁使用而且查找数据规模很庞大的时候可以保存为视图。
4. 注意事项:
- 避免在视图的基础上再创建视图,因为这会降低sql性能和效率。
- 不能在视图里插入数据,不然会报错。
二、子查询
- 什么是子查询?
子查询其实是一次性的视图,在from子句中直接写定义视图的sql查询语句,一个select语句中嵌套了另外一个select语句。当sql语句中有子查询的时候,将会运行括号里面的子查询然后再运行括号外的语句。
例如:
SELECT 性别,人数
FROM (
SELECT 性别,COUNT(*)as人数
FROM student
GROUP BY 性别
)AS 按性别汇总;
2. 如何使用子查询?
- ... in
- ... any
- ... all
出来在from语句中加入select语句以为,我还能在where语句运用in,any 或者 all子查询。
in 子查询
找出每个课程里成绩最低的学号。
此时查询的学号是错误的,是随机产生的。
因为通过group by课程号分组查询出来的最低成绩,此时是没有学号的,而且最低成绩的学号可能会产生两个以上。
/*第一步:查询出每门课程的最低成绩有哪些值*/
SELECT 课程号,MIN(成绩)
FROM score
GROUP BY 课程号;
/*第二步:在成绩表里查找这些值对应的学号*/
SELECT 学号,成绩
FROM score
WHERE 成绩 IN(80,60,80);
/*利用子查询,最终的sql*/
SELECT 学号,成绩
FROM score
WHERE 成绩 IN(
SELECT MIN(成绩)
FROM score
GROUP BY 课程号 /*插入子查询*/
);
!!!可是上述查询语句仍然是错误的!!!(因为这里不能对应每个课程的最低成绩)
正确写法---运用关联子查询
分组取最小值
SELECT *
FROM score as a
WHERE 成绩 IN(
SELECT MIN(成绩)
FROM score as b
WHERE a.课程号=b.课程号
);
any子查询
/*any与比较运算符一起使用*/
SELECT 列名1
FROM 表名1
WHERE 列名1> any (子查询);
例如:哪些学生的成绩比课程0002的全部成绩里的任意一个高尼?
第一步:课程0002的全部成绩,比如(10,30)
第二步:某个学生的成绩大于任意一个第一步里的成绩,就符号条件
SELECT 学号,成绩
FROM score
WHERE 成绩>any(
SELECT 成绩
FROM score
WHERE 课程号= "0002" /*子查询---查找出课程号为0002的全部成绩*/
);
all子查询
例如:哪个学生的成绩比课程0002的全部成绩里的都高尼?
第一步:课程0002的全部成绩,比如(10,30)
第二步:某个学生的成绩大于所有第一步里的成绩,就符号条件
SELECT 学号,成绩
FROM score
WHERE 成绩>all(
SELECT 成绩
FROM score
WHERE 课程号= "0002" /*子查询---查找出课程号为0002的全部成绩*/
);
3. 子查询有什么用?
偶尔使用则用子查询,若经常使用用视图。
4. 注意事项
- all子查询得到的是一个集合不是一个数值
- 不能出现子查询层层嵌套
- as 后面是子查询的名称
5. sql运行顺序
三、标量子查询
- 什么是标量子查询?
在where语句不能使用汇总函数!!!
上述所提到的in,any,all子查询返回的是多行多列的查询结果,但是标量子查询只能返回一行一列的查询结果。标量子查询可以跟比较运算符结合使用。
2. 如何使用标量子查询。
例如:大于平均成绩学生的学号和成绩。
/*大于平均成绩*/
SELECT 学号,成绩
FROM score
WHERE 成绩> (
SELECT AVG(成绩)
FROM score /*----标量子查询----*/
);
例如:查询大于不及格学生平均成绩小于优秀学生平均成绩的学生学号及成绩。
/*差生(成绩<=60)
优秀生(成绩>80)*/
SELECT 学号,成绩
FROM score
WHERE 成绩 BETWEEN(
SELECT AVG(成绩)
FROM score
WHERE 成绩<=60) /*--------不及格学生平均成绩60*/
AND
(SELECT AVG(成绩)
FROM score
WHERE 成绩>80);/*--------优秀学生平均成绩84.15*/
3. 标量子查询有什么用?
- 一般的子查询返回的是多行结果
- 标量子查询返回的是单一值,所有可以与比较运算符或者in,all,any,betwee结合使用形成复杂的子查询。
4.注意事项
标量子查询只能返回单一的值,所有要注意子查询的返回结果是否是单一的,不然容易报错。下图就是一个报错例子。
四、关联子查询
在对每个组里进行比较的时候用关联子查询
例如:查找出每个课程中大于对应课程平均成绩的学生
SELECT 学号,课程号,成绩
FROM score AS s1
WHERE 成绩 > (
SELECT AVG(成绩)
FROM score AS s2
WHERE s1.课程号=s2.课程号 /*关联表的别名与列名*/
GROUP BY 课程号 /*--------此处可以省略*/
);
首先,按课程表分组计算出没组的平均值
然后,根据关联子查询的表每组的平均值与原表格(成绩表)的同一组的数据进行比较。即是说,关联子查询每次比较的是单一的数值。
在内部s2我们可以去对应识别外部s1的数值,但是外部s1的数值不能去对应内部s2。
五、如何用SQL解决业务问题。
翻译成大白话--->写成分析思路--->写成对应的sql子句
哪个学生的成绩比课程0002的全部成绩里的任意一个高。
第一步:课程0002的全部成绩的任意一个。这时候的成绩是一个范围比如(10,30),而非一个值。用select
/*课程0002的全部成绩*/
SELECT 成绩
FROM score
WHERE 课程号="0002";
第二步:某个学生的成绩大于任意一个第一步里的成绩。大于任意一个,用到比较运算符和子查询any语句。
SELECT 学号,成绩
FROM score
WHERE 成绩>any(子查询---第一步的语句)
第三步:写成对应的完全语句。
SELECT 学号,成绩
FROM score
WHERE 成绩>any(
SELECT 成绩
FROM score
WHERE 课程号="0002");
如何看懂sql报错信息?
逐一排查,先运行子查询查看是否有报错,若子查询没有报错则就是外查询出现错误,此时再运行外查询。
六、各种函数
汇总函数
算术函数
字符串函数
日期函数
练习:sqlzoo
List each continent and the name of the country that comes first alphabetically.
SELECT continent,name
FROM world x
WHERE name<=all(
SELECT name
FROM world y
WHERE x.continent=y.continent);
Find the continents where all countries have a population <= 25000000. Then find the names of the countries associated with these continents. Show name, continent and population.
select name,continent,population
from world x
where 25000000>=all(
select population
from world y
where x.continent=y.continent);
Some countries have populations more than three times that of any of their neighbours (in the same continent). Give the countries and continents.
SELECT name, continent
FROM world x
WHERE population>all(
SELECT 3*population
FROM world y
WHERE x.continent=y.continent and x.name<>y.name);