子查询
我的理解:
子查询通常拿来和联合以及分类比较。如果查询条件涉及到了其他的表,就可以使用联合,也可以使用子查询。联合通常是在联合条件为某列和另一列相等的情况下比较方便,通常和group by子句连用。
子查询是在外面查询一个表,在子查询里查询另一个表,且这两个表之间存在某种联系使得子查询被连接到外部查询中。
1.select语句中的子查询
可以将子查询作为SELECT查询内返回一个值的表达式,就像返回单个列一样。但是在一个表达式中子查询必须只返回一个记录,称为标量子查询。
select category,Category.CategoryId,max(dvdprice) from films inner join Category on Category.CategoryId=films.CategoryId group by Category.CategoryId,category; --group by 是针对聚合函数的。并且Category.CategoryId,category都要在group by 子句中 select category,Category.CategoryId,(select max(dvdprice) from films where films.CategoryId=Category.CategoryId) from Category; --利用子查询,和前面的功能一样。选出每类电影里面dvd价格最高的电影价位。
说明:满足films.CategoryId=Category.Categoryid条件的电影有很多,因而会返回多个yearreleased值,但是最大值只会返回一个。
通过where子句,这个子查询被连接到外部的查询中。
去掉max()函数,执行失败,因为会返回多个值。
2.where子句中的子查询
select category,max(DVDPrice),films.FilmName from Category inner join films on films.CategoryId=Category.CategoryId group by category; --错误,filmname不在group表的列中 select category,max(DVDPrice),films.FilmName from Category inner join films on films.CategoryId=Category.CategoryId group by category,filmname; --结果错误,这句话返回的并不是某一类的电影的最低价格,而是一个特定电影类型中一部特定电影的最低价格。必须使用子查询了。 select category,DVDPrice,films.FilmName from Category inner join films on films.CategoryId=Category.CategoryId where films.DVDPrice=(select max(DVDPRICE) from films where films.CategoryId=Category.CategoryId); --这样写就不会返回null的值,因为没有办法判断null是否等于null。 --inner join 只是表示联合的条件,后面子查询中的where联系了外部查询,实现了按categoryid来分类。 --需要找到一种类型电影中的最低的价格,然后返回价格等于最低价格的电影名以及其价格。
比较和上面结果的区别,这里没有返回null。因为where过滤条件里面有一个films.DVDPrice=?,null的等值判断返回的是0.
select max(dvdprice) from films where dvdprice<(select max(DVDPrice) from films); --寻找某一列的第2大的数
3.子查询中的运算符
(1)in运算符
select firstname,lastname,year(dateofbirth) from MemberDetails inner join films on year(DateOfBirth)=YearReleased group by firstname,lastname,year(dateofbirth); --这里的group by 子句不能省,否则会返回所有year(DateOfBirth)=YearReleased的记录,如果相同发行年份的电影有多部,则会用相同的人去匹配这个年份,出现重复记录。利用group by 子句保证了记录的唯一性。 select firstname,lastname,year(dateofbirth) from MemberDetails where year(dateofbirth) in (select yearreleased from films);
select firstname,lastname,year(dateofbirth) from MemberDetails where year(dateofbirth) not in (select yearreleased from films); --当所查找的记录不在一个类里面的时候,用联合则非常困难。 select firstname,lastname,year(dateofbirth) from MemberDetails left out join films on year(DateOfBirth)=YearReleased where yearreleased is null; --这句话和上面的效果一样。外部联合返回了一切年份相等以及不相等的memberdetails中的列,然后用where子句过滤掉了相等发行年份的记录。
(2)ANY,SOME,ALL
--首先any和some是一致的 select firstname,lastname,year(dateofbirth) from MemberDetails where year(dateofbirth)=any(select yearreleased from films); --和前面的in一样 select firstname,lastname,year(dateofbirth) from MemberDetails where year(dateofbirth) <> any(select yearreleased from films); --和前面的not in 一样 select firstname,lastname,year(dateofbirth) from MemberDetails where year(dateofbirth)<any(select yearreleased from films); --也可以在any之前使用其他运算符 select memberid from memberdetails where memberid<all(select filmid from films where filmid>99); --where 2<all(3,9,5)为true,where 7<all(3,9,5)为false
(3)exists运算符
select Category from Category where exists(select * from films where Category.Categoryid=films.CategoryId and rating>3 and (select count(CategoryId) from FavCategory where FavCategory.CategoryId=Category.CategoryId)>=3); --是否存在一个电影类别,有3个以上的成员喜欢它,并且该类里面至少有一部电影的评分在3以上,如果有,则返回该类别。
4.having子句中使用子查询
select city from MemberDetails group by city having avg(year(dateofbirth))>(select avg(year(dateofbirth)) from MemberDetails); --找出这样一个城市,这个城市所有人口的平均出生年龄是比整个memberdetails表里面的人口的平均年龄小的。
5.相关子查询
指访问外部查询的子查询。相关变量是指付给表的别名。
select filmname,rating,dvdprice,category from films as fm1 inner join category as c1 on ca.categoryid=fm1.categoryid where fm1.dvdprice= (slect min(dvdprice) from films as fm2 where fm2.dvdprice is not null and fm1.categoryid=fm2.categoryid and fm2.rating= (select max()fm2.rating) from films as fm3 where fm3.dvdprice is not null and fm2.categoryid=fm3.categoryid group by fm3.categoryid) group by fm2.categoryid) order by fm1.categoryid;
6.其他子句中的子查询
(1)insert子句
insert into favcategory select 7,memberid from memberdetails where lastname='Hawthorn';
(2)update子句
update films set dvdprice=(select max(dvdprice) from films);
(3)delete from子句