MySQL数据库(三)高级数据查询语句

本文详细介绍了SQL中的多表联查,包括非等值查询、等值查询(内联查询)、内联查询的innerjoinon语法、外联查询(leftjoin和rightjoin)以及union操作。同时,讲解了子查询的使用,包括where型、from型、exists型以及any/some/all子查询。此外,还提到了流程控制函数如if和ifnull。这些技巧对于理解和优化SQL查询至关重要。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1,多表联查

非等值查询

语法:select * from 表1,表2

# 多表联查
-- 非等值联查
-- 笛卡尔积
SELECT * FROM student,class;

等值查询

(1)内联查询

语法:select * from 表1,表2 where 表1.字段1 = 表2.字段2...

-- 等值联查
-- 内联查询
SELECT * FROM student,class,sc WHERE student.classid = class.classid AND student.sid  = sc.sid;

SELECT * FROM sc,course WHERE sc.cid = course.cid;

SELECT DISTINCT * FROM student,class,sc,teacher,course WHERE student.Sid =  sc.Sid AND sc.Cid = course.Cid AND course.Tid = teacher.Tid AND student.classid = class.classid;

-- 找到张三老师教过的学生
SELECT student.Sid,Sname,birthday,Ssex,classid FROM teacher,student,sc,course 
WHERE teacher.Tid = course.Tid 
AND course.Cid = sc.Cid 
AND sc.Sid = student.Sid 
AND Tname = '张三';
-- 张三老师教过学生个数,考试平均分
SELECT COUNT(*) 学生个数 ,AVG(score) 平均分 FROM teacher,student,sc,course 
WHERE teacher.Tid = course.Tid 
AND course.Cid = sc.Cid 
AND sc.Sid = student.Sid 
AND Tname = '张三';
-- 每个老师教过的学生个数和平均分
SELECT COUNT(*) 学生个数 ,AVG(score) 平均分,teacher.Tname FROM teacher,student,sc,course 
WHERE teacher.Tid = course.Tid 
AND course.Cid = sc.Cid 
AND sc.Sid = student.Sid GROUP BY teacher.Tid ORDER BY AVG(score) DESC;

(3)内联查询的第二种写法 inner join on 

语法:select * from 表1 inner join 表2 on 条件

-- 内联的第二种写法
-- 表 INNER JOIN ON 关系
SELECT * FROM student 
INNER JOIN class ON student.classid = class.classid 
INNER JOIN sc ON student.Sid = sc.Sid
INNER JOIN course ON sc.Cid = course.Cid
INNER JOIN teacher ON teacher.Tid =  course.Tid
WHERE Tname = '张三';

(4)外联查询 left join in 或 right join on

语法:select * from 表1 left 或 right  join 表2 on 条件;

-- 外联查询要选定一个主表
-- 左外联
-- 表 LEFT JOIN 表 ON 关系
SELECT * FROM student LEFT JOIN class ON student.classid = class.classid; 
-- 右外联
-- 表 RIGHT JOIN 表 ON 关系
SELECT * FROM class RIGHT JOIN student ON student.classid = class.classid;

SELECT Sname,classname,Cname,score,Tname FROM student 
LEFT JOIN class ON student.classid = class.classid 
RIGHT JOIN sc ON student.Sid = sc.Sid 
LEFT JOIN course ON course.Cid =sc.Cid
INNER JOIN teacher ON teacher.Tid =course.Tid;
-- 找到没有班级的学生
SELECT * FROM student LEFT JOIN class ON student.classid = class.classid 
WHERE class.classid IS NULL;
-- 找到没有学生的班级
SELECT * FROM class LEFT JOIN student ON student.classid = class.classid 
WHERE student.sid IS NULL; 
-- 没有考过试的学生
SELECT * FROM student LEFT JOIN sc on student.Sid = sc.Sid 
WHERE sc.score is NULL;

(5)union 求两个查询的并集 

语法:select A.field1 as f1, A.field2 as f2 from <table1> A union select B.field3 as f3, A.field4 as f4 from <table2> B;

注意:

        1,列名不一致时,会以第一张表的表头为准,并对其栏目。

        2,会将重复的行过滤掉。

        3,如果查询的表的列数量不相等时,会报错。

        4,在每个子句中的排序是没有意义的,mysql在进行合并的时候会忽略掉。

        5,如果子句中的排序和limit进行结合是有意义的。        

        6,可以对合并后的整表进行排序。

        7,union会过滤重复数据,union all不会过滤重复数据。

-- UNION 找到两个集合的并集
-- 数据类型没有关系
-- 两个结果

-- 找到没有学生的班级和没有班级的学生
SELECT * FROM student LEFT JOIN class ON student.classid = class.classid 
WHERE class.classid IS NULL
UNION
SELECT * FROM class LEFT JOIN student ON student.classid = class.classid 
WHERE student.sid IS NULL;

SELECT * FROM student RIGHT JOIN class ON student.classid = class.classid
UNION
SELECT * FROM class RIGHT JOIN student ON student.classid = class.classid;

-- 获取所有班级和所学生的信息
-- union 去除重复的数据  
-- 添加 all 不再去除重复,全部显示
select * from student left join class
	on student.classid = class.classid
union all
select * from student right join 	class
	on student.classid = class.classid

2,子查询 内部查询

(1)where 型

# 子查询
-- 所有的子查询必须要用小括号括起来
-- where 子查询
-- 查询 id 最大的一个学生(排序,分页)
SELECT * FROM student ORDER BY Sid DESC LIMIT 1;
-- max 最大的id
SELECT * FROM student WHERE Sid = (SELECT MAX(Sid) FROM student);
-- 学过张三老师课程的学生
SELECT * FROM student WHERE Sid IN (SELECT Sid FROM sc WHERE cid = (SELECT cid FROM course WHERE Tid = (SELECT Tid FROM teacher WHERE tname = '张三' )));
-- 没有学过张三老师课程的学生
SELECT * FROM student WHERE Sid NOT IN (SELECT Sid FROM sc WHERE cid = (SELECT cid FROM course WHERE Tid = (SELECT Tid FROM teacher WHERE tname = '张三' )));
-- 查询,每个班id最大的学生(使用where子查询实现)
SELECT * FROM student,class WHERE student.classid = class.classid AND Sid IN (SELECT MAX(Sid) FROM student GROUP BY classid);
SELECT * FROM student LEFT JOIN class ON student.classid = class.classid WHERE  Sid IN (SELECT MAX(Sid) FROM student GROUP BY classid);
-- 查询大于等于2人的班级名称和人数
SELECT classname,COUNT(Sid) FROM class LEFT JOIN student ON student.classid = class.classid GROUP BY class.classid HAVING COUNT(sid) >= 2;

(2)from型 把内层的查询结果当成临时表,供外层sql再次查询。

-- FROM 子查询
-- 查询大于等于5人的班级名称和人数
SELECT classname,COUNT(Sid) FROM class LEFT JOIN student ON student.classid = class.classid GROUP BY class.classid HAVING COUNT(sid) >= 2;
-- FROM 子查询  查询大于等于5人的班级名称和人数
-- FROM 子查询 要给子查询起一个表名
SELECT classname,人数 FROM class INNER JOIN 
(SELECT classid,COUNT(*) 人数 FROM student GROUP BY classid ) t1 ON class.classid = t1.classid 
WHERE 人数 >= 4;
-- FROM 子查询 
-- 每个班级的考试次数和平均分
-- 班级名称 考试次数,平均分
SELECT * FROM class LEFT JOIN (SELECT classid,COUNT(sc.sid),AVG(score) FROM student LEFT JOIN sc ON student.Sid = sc.Sid GROUP BY classid) t1 ON class.classid = t1.classid;

SELECT classname 班级,COUNT(sc.Sid) 考试次数,AVG(score) 平均分 FROM student,sc,class WHERE student.classid = class.classid AND student.Sid = sc.Sid GROUP BY class.classid;

(3)exists型 把外层sql的结果,拿到内层sql去测试,如果内层的sql成立,则该行取出。内层查询是exists后的查询。

-- EXISTS 子查询
SELECT * FROM teacher WHERE EXISTS (SELECT * FROM student WHERE Ssex = '男');

(4)any,some,all 

-- ANY SOME ALL 子查询
-- 查询出一班成绩比二班最低成绩高的学生
SELECT DISTINCT student.* FROM student INNER JOIN sc ON student.Sid = sc.Sid 
WHERE classid = 1 AND score > ANY (SELECT score FROM student INNER JOIN sc ON student.Sid = sc.Sid WHERE classid = 2);
SELECT DISTINCT student.* FROM student INNER JOIN sc ON student.Sid = sc.Sid 
WHERE classid = 1 AND score > SOME (SELECT score FROM student INNER JOIN sc ON student.Sid = sc.Sid WHERE classid = 2);
-- ALL 子查询
-- 查询
SELECT DISTINCT student.* FROM student INNER JOIN sc ON student.Sid = sc.Sid 
WHERE classid = 1 AND score > ALL (SELECT score FROM student INNER JOIN sc ON student.Sid = sc.Sid
WHERE classid = 2);

3,流程控制函数

(1)if(expr1,expr2,expr3)     如果expr1 条件成立,则执行expr2,如果条件不成立,则执行expr3

-- IF(expr1,expr2,expr3)
-- expr1 条件
-- expr2 条件成立的结果
-- expr3 条件不成立的结果
SELECT tid,tname,IF(tsex = '1','男','女') 性别,tbirthday
FROM teacher;

(2)ifnull(expr1,expr2)        如果expr1不为Null,则执行expr1,如果expr1为Null,则执行expr2

-- IFNULL (expr1,expr2)
-- expr1 字段名
-- expr2 默认值
SELECT sid,sname,IFNULL(birthday,'2000-2-2') FROM student;

(3)case when then end

①简单case函数

语法:case 字段名 when 常量 then 结果 end;

-- 简单case
-- CASE 字段名 WHEN 常量 THEN 结果 END;
SELECT Tid,tname,CASE tsex WHEN 1 THEN '男' WHEN 0 THEN '女' ELSE '未知' END,temail,tmoney FROM teacher;

②搜素case函数

语法:case when 条件 then 结果 end;

-- 搜素case 常用
-- CASE WHEN 条件 THEN 结果 END
SELECT tid,tname,CASE WHEN tsex = 1 THEN '男' WHEN Tsex <> 1 THEN '女' END,temail,tmoney FROM teacher; 
-- 查询学生的成绩,并将大于90分的用A显示,大于80分的用B显示,大于70分的用C显示,大于60分的用D显示,小于60分的显示不及格
SELECT student.Sid,Sname,birthday,Ssex,classid, CASE 
WHEN score >= 90 AND score <= 100 THEN 'A'
WHEN score >= 80 AND score < 90 THEN 'B'
WHEN score >= 70 AND score < 80 THEN 'C'
WHEN score >= 60 AND score < 70 THEN 'D'
WHEN score < 60 THEN '不及格' END 成绩
FROM student INNER JOIN sc ON student.Sid = sc.Sid ;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

手可摘鑫晨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值