• mysql高级查询


    Exists子查询

    Exists的特点

             1.在执行createdrop语句前,可以使用exists语句来判断数据库对象是否存在,返回值是truefalse

                 比如  

     drop   table    if  exists  student;  意思是如果存在表student则删除!否则不删除!

     Create  table   if  not  exists  student;   意思是如果不存在表student则创建,否则不创建!

             2.exists还可以作为where条件的子查询

                    Select  ..... from  表名  where  exists (子查询);

                    意思是:

                         如果子查询有结果,则返回值为true,继续执行外层的查询语句;

                         如果子查询没有结果,则返回值是false,外层的查询语句不会执行。

                      

                  

    -- 检查“高等数学-1” 课程最近一次考试成绩

    -- 如果有 80分以上的成绩,显示分数排在前5名的学员学号和分数

    --  不使用exists

    -- 01.查询“高等数学-1” 课程 对应的编号

    SELECT subjectNo FROM `subject`

    WHERE SubjectName='高等数学-1'

    -- 02.查询最近的考试成绩

    SELECT MAX(ExamDate) FROM result

    WHERE SubjectNo=(SELECT subjectNo FROM `subject`

    WHERE SubjectName='高等数学-1')

    -- 03. 02的基础上 加条件 成绩大于80

    SELECT * FROM result

    WHERE ExamDate=

    (SELECT MAX(ExamDate) FROM result

    WHERE SubjectNo=(SELECT subjectNo FROM `subject`

    WHERE SubjectName='高等数学-1'))

    AND StudentResult>80

    -- 04.优化

    SELECT studentNo,StudentResult FROM result

    WHERE ExamDate=

    (SELECT MAX(ExamDate) FROM result

    WHERE SubjectNo=(SELECT subjectNo FROM `subject`

    WHERE SubjectName='高等数学-1'))

    AND StudentResult>80

    ORDER BY StudentResult DESC

    LIMIT 0,5

    --  使用exists

    -- 检查“高等数学-1” 课程最近一次考试成绩

    -- 如果有 80分以上的成绩,显示分数排在前5名的学员学号和分数

    -- 01.查询“高等数学-1” 课程 对应的编号

    SELECT subjectNo FROM `subject`

    WHERE SubjectName='高等数学-1'

    -- 02.查询最近的考试成绩

    SELECT MAX(ExamDate) FROM result

    WHERE SubjectNo=(SELECT subjectNo FROM `subject`

    WHERE SubjectName='高等数学-1')

    -- 03.查询学号和成绩

    SELECT StudentNo,StudentResult FROM result

    WHERE  EXISTS

    (

    SELECT * FROM result

    WHERE subjectNo=(

    SELECT subjectNo FROM `subject`

    WHERE SubjectName='高等数学-1'

    )

    AND ExamDate=(

    SELECT MAX(ExamDate) FROM result

    WHERE SubjectNo=(SELECT subjectNo FROM `subject`

    WHERE SubjectName='高等数学-1')

    )

    AND StudentResult>80

    )

    AND subjectNo=(

    SELECT subjectNo FROM `subject`

    WHERE SubjectName='高等数学-1'

    )

    AND ExamDate=(

    SELECT MAX(ExamDate) FROM result

    WHERE SubjectNo=(SELECT subjectNo FROM `subject`

    WHERE SubjectName='高等数学-1')

    )

    ORDER BY StudentResult DESC

    LIMIT 0,5

    Not Exists子查询

    -- 检查“高等数学-1”课程最近一次考试成绩

    -- 如果全部未通过考试(60分及格),认为本次考试偏难,计算的该次考试平均分加5

    -- 01.查询“高等数学-1” 课程 对应的编号

    SELECT subjectNo FROM `subject`

    WHERE SubjectName='高等数学-1'

    -- 02.查询最近的考试成绩

    SELECT MAX(ExamDate) FROM result

    WHERE SubjectNo=(SELECT subjectNo FROM `subject`

    WHERE SubjectName='高等数学-1')

    -- 03.查询成绩大于60的  反着来

    SELECT StudentResult FROM result

    WHERE StudentResult>60

    AND SubjectNo=(

    SELECT subjectNo FROM `subject`

    WHERE SubjectName='高等数学-1'

    )

    AND ExamDate=(

    SELECT MAX(ExamDate) FROM result

    WHERE SubjectNo=(SELECT subjectNo FROM `subject`

    WHERE SubjectName='高等数学-1')

    )

    -- 04. 如果全部未通过考试,考试平均分加5

    SELECT AVG(StudentResult)+5  FROM result

    WHERE NOT EXISTS

    (

    SELECT StudentResult FROM result

    WHERE StudentResult>60

    AND SubjectNo=(

    SELECT subjectNo FROM `subject`

    WHERE SubjectName='高等数学-1'

    )

    AND ExamDate=(

    SELECT MAX(ExamDate) FROM result

    WHERE SubjectNo=(SELECT subjectNo FROM `subject`

    WHERE SubjectName='高等数学-1')

    )

    )

    AND SubjectNo=(

    SELECT subjectNo FROM `subject`

    WHERE SubjectName='高等数学-1'

    )

    AND ExamDate=(

    SELECT MAX(ExamDate) FROM result

    WHERE SubjectNo=(SELECT subjectNo FROM `subject`

    WHERE SubjectName='高等数学-1')

    )

    -- 如果有 年级名称是大二 的学生,就 查询出 年级名称是大一的 所有学生信息

    --  01.先查询出 对应的年级编号

    SELECT GradeId FROM grade  WHERE GradeName='大一'

    SELECT GradeId FROM grade  WHERE GradeName='大二'

    --  02.在学生表中是否存在  年级名称是大二 的学生

    SELECT * FROM  student  WHERE  gradeID=(

    SELECT GradeId FROM grade  WHERE GradeName='大二'

    )

    -- 03.如果有查询出 年级名称是大一的 所有学生信息

    SELECT * FROM student

    WHERE  EXISTS

    (

    SELECT * FROM  student  WHERE  gradeID=(

    SELECT GradeId FROM grade  WHERE GradeName='大二'

    )

    )

    AND GradeId=(

    SELECT GradeId FROM grade  WHERE GradeName='大一'

    )

    ExistsIN , Not ExistsNot IN 的区别

     01. INNot IN 做的是一个区间的判断,查询数据是否在区间内

            ExistsNot Exists都是根据查询语句返回true或者false!

         

         02.  例子:

    select  a.* from  A  a

     where  a.id  in(select id from B)

      如果A表中有1000条数据

           B表中有1000条数据

      分析步骤:

          01. select id from B 会查询出B表中的所有id,然后缓存起来,共1000条(因为使用in 会先执行子查询

          02.然后分别拿A表中的每一个idB表中的1000id进行比较,也就是比较了 1000*1000

          03.这样效率是非常慢的

          04.如果B表中只有100或者10条数据(只是举例说明数据量小),那么就会比较1000*10

             这样相对来说效率会高点!

     结论:

    子查询中涉及的表(B)数据量小于 主查询中涉及的表(A)数据量 时,使用In来查询!可以提高效率

    In 查询做的是 外表和内表的hash连接

    hash连接就是  以 外层查询的表作为hash table ,内层查询的表在hash table中查询数据!

     很显然,如果内层查询的数量大 ,查询效率就慢,查询数据量小,效率就高!

    03. 例子:

      select  a.* from  A  a

     where  exists  (select id from B b where a.id=b.id)

      如果A表中有1000条数据

           B表中有1000条数据

      分析步骤:

          01. 使用了exists会以外层查询为驱动)上面的sql语句只会执行1000次(因为A表中有多少条数据,就会执行几次)

          02. exists查询不需要数据的结果集,只需要返回true或者false

    结论:

    子查询中涉及的表(B)数据量大于 主查询中涉及的表(A)数据量时,使用exists来查询!可以提高效率

    Exists查询做的是loop循环

     04. 如果子查询中涉及的表(B)数据量 和 主查询中涉及的表(A)数据量 差不多时,建议使用IN来查询!

         因为In查询是在内存中的查询,exists需要查询数据库,所以内存中的查询肯定比查询数据库性能高!

     05.not exists 在任何时候都比not in 效率高!

              因为not in 那么内外表都进行全表扫描,没有用到索引not  exists的子查询仍然可以用到索引!

    any,some,all的使用

    SELECT * FROM student

    WHERE studentname

    IN(SELECT studentName FROM student)

    --  使用any(只要是在区间就行) 替换in   

    SELECT * FROM student

    WHERE studentname=ANY(SELECT studentName FROM student)

    -- all  满足子查询中编号最大的

    SELECT * FROM student WHERE

    studentNo>ALL

    (SELECT studentNo FROM student WHERE studentNo IN(1014,1001,1002))

    -- any   满足子查询中编号最小的

    SELECT * FROM student WHERE

    studentNo>ANY

    (SELECT studentNo FROM student WHERE studentNo IN(1014,1001,1002))

    --  和  any 效果一致

    SELECT * FROM student WHERE

    studentNo>SOME

    分组查询

    -- 分组  group by

    --  01. 查询 每门课程的名称 以及平均分

    --  并且按照平均分降序排列

    SELECT  subjectName,AVG(StudentResult)

    FROM  `result` r,`subject` s

    WHERE

    r.`SubjectNo`=s.`SubjectNo`

    GROUP BY subjectName

    ORDER BY AVG(StudentResult) DESC

    -- 02.在上述案例中增加   条件  having

    --  平均分>73的 显示

    SELECT  subjectName,AVG(StudentResult)

    FROM  `result` r,`subject` s

    WHERE

    r.`SubjectNo`=s.`SubjectNo`

    GROUP BY subjectName

    HAVING AVG(StudentResult)>73

    ORDER BY AVG(StudentResult) DESC

    -- 03.统计每个年级的男女人数   多列进行分组

    SELECT   gradeid '年级编号',COUNT(sex) '性别人数',sex '性别'

    FROM student

    WHERE sex IS NOT NULL AND gradeid IS NOT NULL

    GROUP BY gradeid,sex

    -- 04. 找出每个课程成绩的前三名

    SELECT * FROM result r1

    WHERE

    (

    SELECT  COUNT(1) FROM  result r2

    WHERE r1.subjectNo=r2.`SubjectNo`

    AND r1.studentresult<r2.studentresult

    )<3

    ORDER BY subjectNo,studentResult DESC

    多表连接查询

    比如之前写的小例子,查询学生的成绩,我们获取的是学生编号和成绩!

    但是如果获取了学生姓名和成绩岂不是更好? 但是学生姓名和成绩不在一张表中!

    这时候就需要我们的连接查询!

          常用的连接查询方式:

    01. 内连接

    02. 外连接

    内连接

    内连接是典型的最常用的连接查询! 特点就是两个表中存在主外健关系时,通常使用!

            查询两张表中共同的数据!

          

           内连接的实现方式有两种:

         

          01. where条件中指定连接条件

                比如 查询学生姓名以及对应的年级名称

                Select  studentName,gradeName

     from student,grade

    Where student.gradeId=grade.gradeId

          

          02.form 子句中增加 inner join  on 关系

            比如查询学生姓名,科目名称以及考试成绩

    SELECT  studentName,subjectName,studentresult

    FROM student s

    INNER JOIN result r ON s.studentNo=r.studentNo

    INNER JOIN  `subject` su ON  su.subjectNo=r.subjectNo

     注意点:

      001.inner可以省略

      002.inner join 用来连接两个表

      003.on用来设置条件

      004. s  r  su是用的别名

    外连接

    外连接查询是至少返回一个表中的所有记录,根据匹配条件有选择地返回另一张表的数据!

             外连接有主表和从表的概念!

             以主表为准匹配从表的数据,符合连接条件的数据直接返回到结果集中,不符合的数据将被赋予null之后再返回到结果集中!

                   外连接查询又分为:

    01.左外连接    Left  outer  join

    以左表为主表,从表(右边的表)中如果没有匹配的数据返回null

    例子1: 查询学生的姓名,考试科目以及成绩!

    SELECT  studentName,subjectNo,studentResult FROM  student s

    LEFT JOIN  result r  ON r.`studentNo`=s.`studentNo`

    例子2:查询所有科目对应的学生成绩

    SELECT  subjectName,s.subjectNo,studentResult FROM

    `subject`  s LEFT JOIN result r

    ON s.`SubjectNo`=r.`SubjectNo`

    02.右外连接 right outer  join

    以右表为主表,从表(左边的表)中如果没有匹配的数据返回null

      例子:查询年级名称和学生名称       两个结果是否一致?

                             SELECT gradeName,studentName FROM grade

    RIGHT JOIN student ON grade.`GradeID`=student.`GradeId`

    SELECT gradeName,studentName FROM grade

    INNER JOIN student ON grade.`GradeID`=student.`GradeId`

  • 相关阅读:
    pydbg系列[1]
    内核参与方式
    Debugging with GDB阅读[6]
    宏技巧解读
    右键-发送到-邮件接收者没有了的解决方法
    获得文件版本信息
    解决动态生成的SQL中特殊字符的问题 QuotedStr function
    CreateFileMapping的MSDN翻译和使用心得
    关闭Windows自动播放功能
    清凉明目茶
  • 原文地址:https://www.cnblogs.com/yunfeioliver/p/9416092.html
Copyright © 2020-2023  润新知