zoukankan      html  css  js  c++  java
  • MySQL(多表的表记录的查询)

    一、外键约束

    1、创建外键

    复制代码
    ---  每一个班主任会对应多个学生 , 而每个学生只能对应一个班主任
    
    ----主表
    CREATE TABLE ClassCharger(
    
           id TINYINT PRIMARY KEY auto_increment,
           name VARCHAR (20),
           age INT ,
           is_marriged boolean  -- show create table ClassCharger: tinyint(1)
    );
    
    INSERT INTO ClassCharger (name,age,is_marriged) VALUES ("冰冰",12,0),
                                                           ("丹丹",14,0),
                                                           ("歪歪",22,0),
                                                           ("姗姗",20,0),
                                                           ("小雨",21,0);
    ----子表
    CREATE TABLE Student(
    
           id INT PRIMARY KEY auto_increment,
           name VARCHAR (20),
           charger_id TINYINT,     --切记:作为外键一定要和关联主键的数据类型保持一致
           -- [ADD CONSTRAINT charger_fk_stu]FOREIGN KEY (charger_id) REFERENCES ClassCharger(id)
    ) ENGINE=INNODB;
    
    INSERT INTO Student(name,charger_id) VALUES ("alvin1",2),
                                                ("alvin2",4),
                                                ("alvin3",1),
                                                ("alvin4",3),
                                                ("alvin5",1),
                                                ("alvin6",3),
                                                ("alvin7",2);
    DELETE FROM ClassCharger WHERE name="冰冰";
    INSERT student (name,charger_id) VALUES ("yuan",1);
    -- 删除居然成功,可是 alvin3显示还是有班主任id=1的冰冰的;
    
    -----------增加外键和删除外键---------
    
    ALTER TABLE student  ADD CONSTRAINT abc
                         FOREIGN KEY(charger_id)
                         REFERENCES  classcharger(id);
    
    ALTER TABLE student DROP FOREIGN KEY abc;
    复制代码

    2、 INNODB支持的ON语句

    复制代码
    --外键约束对子表的含义:   如果在父表中找不到候选键,则不允许在子表上进行insert/update
    
    --外键约束对父表的含义:    在父表上进行update/delete以更新或删除在子表中有一条或多条对
                         -- 应匹配行的候选键时,父表的行为取决于:在定义子表的外键时指定的
                         -- on update/on delete子句
    
    
    -----------------innodb支持的四种方式---------------------------------------
    
    -----cascade方式 在父表上update/delete记录时,同步update/delete掉子表的匹配记录
    -----外键的级联删除:如果父表中的记录被删除,则子表中对应的记录自动被删除--------
    
         FOREIGN KEY (charger_id) REFERENCES ClassCharger(id)
                                  ON DELETE CASCADE
    
    
    ------set null方式 在父表上update/delete记录时,将子表上匹配记录的列设为null
       -- 要注意子表的外键列不能为not null
    
         FOREIGN KEY (charger_id) REFERENCES ClassCharger(id)
                                  ON DELETE SET NULL
    
    
    ------Restrict方式 :拒绝对父表进行删除更新操作(了解)
    
    ------No action方式 在mysql中同Restrict,如果子表中有匹配的记录,则不允许对父表对应候选键
       -- 进行update/delete操作(了解)
    复制代码

    二、多表查询

     准备表和数据

    1、多表查询之连接查询

    1.笛卡尔积查询

    复制代码
    mysql> SELECT * FROM employee,department;
    
    --        select employee.emp_id,employee.emp_name,employee.age,
    --        department.dept_name from employee,department;
    
    +--------+----------+------+---------+---------+-----------+
    | emp_id | emp_name | age  | dept_id | dept_id | dept_name |
    +--------+----------+------+---------+---------+-----------+
    |      1 | A        |   19 |     200 |     200 | 人事部    |
    |      1 | A        |   19 |     200 |     201 | 技术部    |
    |      1 | A        |   19 |     200 |     202 | 销售部    |
    |      1 | A        |   19 |     200 |     203 | 财政部    |
    |      2 | B        |   26 |     201 |     200 | 人事部    |
    |      2 | B        |   26 |     201 |     201 | 技术部    |
    |      2 | B        |   26 |     201 |     202 | 销售部    |
    |      2 | B        |   26 |     201 |     203 | 财政部    |
    |      3 | C        |   30 |     201 |     200 | 人事部    |
    |      3 | C        |   30 |     201 |     201 | 技术部    |
    |      3 | C        |   30 |     201 |     202 | 销售部    |
    |      3 | C        |   30 |     201 |     203 | 财政部    |
    |      4 | D        |   24 |     202 |     200 | 人事部    |
    |      4 | D        |   24 |     202 |     201 | 技术部    |
    |      4 | D        |   24 |     202 |     202 | 销售部    |
    |      4 | D        |   24 |     202 |     203 | 财政部    |
    |      5 | E        |   20 |     200 |     200 | 人事部    |
    |      5 | E        |   20 |     200 |     201 | 技术部    |
    |      5 | E        |   20 |     200 |     202 | 销售部    |
    |      5 | E        |   20 |     200 |     203 | 财政部    |
    |      6 | F        |   38 |     204 |     200 | 人事部    |
    |      6 | F        |   38 |     204 |     201 | 技术部    |
    |      6 | F        |   38 |     204 |     202 | 销售部    |
    |      6 | F        |   38 |     204 |     203 | 财政部    |
    +--------+----------+------+---------+---------+-----------+
    复制代码

    2.内连接

    复制代码
    -- 查询两张表中都有的关联数据,相当于利用条件从笛卡尔积结果中筛选出了正确的结果。
    
      select * from employee,department where employee.dept_id = department.dept_id;
    --select * from employee inner join department on employee.dept_id = department.dept_id;
    
          +--------+----------+------+---------+---------+-----------+
          | emp_id | emp_name | age  | dept_id | dept_id | dept_name |
          +--------+----------+------+---------+---------+-----------+
          |      1 | A        |   19 |     200 |     200 | 人事部    |
          |      2 | B        |   26 |     201 |     201 | 技术部    |
          |      3 | C        |   30 |     201 |     201 | 技术部    |
          |      4 | D        |   24 |     202 |     202 | 销售部    |
          |      5 | E        |   20 |     200 |     200 | 人事部    |
          +--------+----------+------+---------+---------+-----------+
    复制代码

    3.外连接

    复制代码
    --(1)左外连接:在内连接的基础上增加左边有右边没有的结果
    
     select * from employee left join department on employee.dept_id = department.dept_id;
    
         +--------+----------+------+---------+---------+-----------+
        | emp_id | emp_name | age  | dept_id | dept_id | dept_name |
        +--------+----------+------+---------+---------+-----------+
        |      1 | A        |   19 |     200 |     200 | 人事部    |
        |      5 | E        |   20 |     200 |     200 | 人事部    |
        |      2 | B        |   26 |     201 |     201 | 技术部    |
        |      3 | C        |   30 |     201 |     201 | 技术部    |
        |      4 | D        |   24 |     202 |     202 | 销售部    |
        |      6 | F        |   38 |     204 |    NULL | NULL      |
        +--------+----------+------+---------+---------+-----------+
    
     --(2)右外连接:在内连接的基础上增加右边有左边没有的结果
    
     select * from employee RIGHT JOIN department on employee.dept_id = department.dept_id;
    
            +--------+----------+------+---------+---------+-----------+
            | emp_id | emp_name | age  | dept_id | dept_id | dept_name |
            +--------+----------+------+---------+---------+-----------+
            |      1 | A        |   19 |     200 |     200 | 人事部    |
            |      2 | B        |   26 |     201 |     201 | 技术部    |
            |      3 | C        |   30 |     201 |     201 | 技术部    |
            |      4 | D        |   24 |     202 |     202 | 销售部    |
            |      5 | E        |   20 |     200 |     200 | 人事部    |
            |   NULL | NULL     | NULL |    NULL |     203 | 财政部    |
            +--------+----------+------+---------+---------+-----------+
    
     --(3)全外连接:在内连接的基础上增加左边有右边没有的和右边有左边没有的结果
    
        -- mysql不支持全外连接 full JOIN
        -- mysql可以使用此种方式间接实现全外连接
        
       select * from employee RIGHT JOIN department on employee.dept_id = department.dept_id
       UNION
       select * from employee LEFT JOIN department on employee.dept_id = department.dept_id;
            +--------+----------+------+---------+---------+-----------+
            | emp_id | emp_name | age  | dept_id | dept_id | dept_name |
            +--------+----------+------+---------+---------+-----------+
            |      1 | A        |   19 |     200 |     200 | 人事部    |
            |      2 | B        |   26 |     201 |     201 | 技术部    |
            |      3 | C        |   30 |     201 |     201 | 技术部    |
            |      4 | D        |   24 |     202 |     202 | 销售部    |
            |      5 | E        |   20 |     200 |     200 | 人事部    |
            |   NULL | NULL     | NULL |    NULL |     203 | 财政部    |
            |      6 | F        |   38 |     204 |    NULL | NULL      |
            +--------+----------+------+---------+---------+-----------+
    
          -- 注意 union与union all的区别:union会去掉相同的纪录
    复制代码

    2、多表查询之复合条件连接查询

    复制代码
    -- 查询员工年龄大于等于25岁的部门
    
        SELECT DISTINCT department.dept_name
        FROM employee,department
        WHERE employee.dept_id = department.dept_id
        AND age>25;
    
    
    --以内连接的方式查询employee和department表,并且以age字段的升序方式显示
    
        select employee.emp_id,employee.emp_name,employee.age,department.dept_name
        from employee,department
        where employee.dept_id = department.dept_id
        order by age asc;
    复制代码

    3、多表查询之子查询

    复制代码
    -- 子查询是将一个查询语句嵌套在另一个查询语句中。
    -- 内层查询语句的查询结果,可以为外层查询语句提供查询条件。
    -- 子查询中可以包含:IN、NOT IN、ANY、ALL、EXISTS 和 NOT EXISTS等关键字
    -- 还可以包含比较运算符:= 、 !=、> 、<等
    
    -- 1. 带IN关键字的子查询
    
       ---查询employee表,但dept_id必须在department表中出现过
    
       select * from employee
                where dept_id IN
                (select dept_id from department);
    
    +--------+----------+------+---------+
    | emp_id | emp_name | age  | dept_id |
    +--------+----------+------+---------+
    |      1 | A        |   19 |     200 |
    |      2 | B        |   26 |     201 |
    |      3 | C        |   30 |     201 |
    |      4 | D        |   24 |     202 |
    |      5 | E        |   20 |     200 |
    +--------+----------+------+---------+
    5 rows in set (0.01 sec)
    
    -- 2. 带比较运算符的子查询
          --      =、!=、>、>=、<、<=、<>
    
         -- 查询员工年龄大于等于25岁的部门
         select dept_id,dept_name from department
               where dept_id IN
              (select DISTINCT dept_id from employee where age>=25);
    
    -- 3. 带EXISTS关键字的子查询
    
    -- EXISTS关字键字表示存在。在使用EXISTS关键字时,内层查询语句不返回查询的记录。
    -- 而是返回一个真假值。Ture或False
    -- 当返回Ture时,外层查询语句将进行查询;当返回值为False时,外层查询语句不进行查询
    
         select * from employee
                  WHERE EXISTS
                  (SELECT dept_name from department where dept_id=203);
    
          --department表中存在dept_id=203,Ture
    
    
         select * from employee
                    WHERE EXISTS
                  (SELECT dept_name from department where dept_id=205);
    
         -- Empty set (0.00 sec)
    
    
        ps:  create table t1(select * from t2);
    复制代码

     三、课后练习

    练习一:

    1、将所有的课程的名称以及对应的任课老师姓名打印出来

    SELECT cid,cname,tname FROM course LEFT JOIN teacher on course.teacher_id=teacher.tid;

    2、查询学生表中男女生各有多少人

    SELECT gender,COUNT(gender) 人数 FROM student GROUP BY gender;

    3、查询物理成绩等于100的学生的姓名

    SELECT sid,sname FROM student WHERE sid in (SELECT student_id FROM score WHERE course_id=(SELECT cid FROM course WHERE cname='物理') and num=100);

    4、查询平均成绩大于八十分的同学的姓名和平均成绩

    SELECT sname,AVG(num) FROM student,score WHERE student.sid=score.student_id GROUP BY student_id HAVING AVG(num)>80;

    5、查询所有学生的学号,姓名,选课数,总成绩

    SELECT student_id 学号 ,sname 姓名,COUNT(course_id) 选课数,SUM(num) 总成绩 FROM student,score WHERE student.sid=student_id GROUP BY student_id;

    6、查询姓李老师的个数

    SELECT COUNT(tname) 姓李老师个数 from teacher WHERE tname like '李%';

    7、查询没有报李平老师课的学生姓名

    SELECT sid,sname FROM student WHERE sid NOT IN (SELECT distinct student_id from score LEFT JOIN student on student_id=student.sid WHERE course_id in (SELECT cid from course,teacher WHERE teacher_id=tid and tname='李平老师'));

    mysql> select sid,sname from student where sid not in (SELECT distinct student_id from score where course_id in (SELECT cid from course,teacher WHERE teacher_id=tid and tname='李平老师'));

    8、查询物理课程比生物课程高的学生的学号

    SELECT A.student_id FROM 
    (SELECT * FROM score WHERE course_id=(SELECT cid FROM course WHERE cname='物理'))A
    INNER JOIN
    (SELECT * FROM score WHERE course_id=(SELECT cid FROM course WHERE cname='生物')) B ON A.student_id = B.student_id WHERE A.num>B.num

    9、查询没有同时选修物理课程和体育课程的学生姓名

    SELECT sid,sname from student WHERE sid NOT IN (SELECT student_id from score WHERE course_id in (2,3) GROUP BY student_id HAVING COUNT(student_id)=2);

    10、查询挂科超过两门(包括两门)的学生姓名和班级

    SELECT sname,caption FROM student,class WHERE class_id=cid and sid IN (SELECT student_id FROM score WHERE num<60 GROUP BY student_id HAVING COUNT(student_id)>=2);

    11 、查询选修了所有课程的学生姓名

    SELECT sname FROM student WHERE sid in (SELECT student_id FROM score  GROUP BY student_id HAVING COUNT(course_id)=(SELECT COUNT(cid) FROM course));

    12、查询李平老师教的课程的所有成绩记录

    SELECT sid,sname,cname,num FROM  student RIGHT JOIN (SELECT student_id,cname,num FROM  score,course WHERE course_id=cid AND course_id in (SELECT cid from course,teacher WHERE teacher_id=tid and tname='李平老师')) ls on ls.student_id=student.sid;

    13、查询选课学生都选修了的课程号和课程名

    SELECT cid,cname FROM course WHERE cid =(SELECT course_id from score GROUP BY course_id HAVING COUNT(student_id)=(select count(distinct student_id) from score))

    练习二:

    14、查询每门课程被选修的次数

    SELECT course_id,cname,COUNT(course_id) 被选课次数 FROM score,course WHERE cid=course_id GROUP BY course_id;

    15、查询只选修了一门课程的学生姓名和学号

    SELECT sid,sname FROM student WHERE sid =(SELECT student_id FROM score GROUP BY student_id HAVING COUNT(course_id)=1);

    16、查询所有学生考出的成绩并按从高到低排序(成绩去重)

    SELECT DISTINCT num FROM score ORDER BY num DESC;

    17、查询平均成绩大于85的学生姓名和平均成绩

     SELECT sname,AVG(num) FROM score,student WHERE student_id =student.sid GROUP BY student_id HAVING AVG(num)>85;

    18、查询生物成绩不及格的学生姓名和对应生物分数

    SELECT sname,num FROM score,student WHERE student_id=student.sid AND course_id=(SELECT cid FROM course WHERE cname='生物') and num<60;

    19、查询在所有选修了李平老师课程的学生中,这些课程(李平老师的课程,不是所有课程)平均成绩最高的学生姓名

    SELECT student_id,sname,AVG(num) FROM score,student WHERE student_id=student.sid AND course_id in (SELECT cid FROM course WHERE teacher_id =( SELECT tid FROM teacher WHERE tname like '李平%')) GROUP BY student_id  ORDER BY AVG(num) DESC LIMIT 1;

    20、查询每门课程成绩最好的前两名学生姓名

    21、查询不同课程但成绩相同的学号,课程号,成绩

    SELECT * FROM score WHERE student_id IN (SELECT student_id FROM score GROUP BY num,student_id HAVING COUNT(student_id)>=2);

    22、查询没学过“李平”老师课程的学生姓名以及选修的课程名称;

    SELECT * from score WHERE student_id NOT IN (select distinct student_id from score where course_id in (SELECT cid FROM
    course WHERE teacher_id =( SELECT tid FROM teacher WHERE tname like '李平%')));

    23、查询所有选修了学号为1的同学选修过的一门或者多门课程的同学学号和姓名;

    SELECT sid,sname FROM student WHERE sid IN (SELECT DISTINCT student_id FROM score WHERE course_id IN (SELECT course_id from score WHERE student_id=1) AND student_id!=1);

    24、任课最多的老师中学生单科成绩最高的学生姓名

    SELECT sname FROM student WHERE sid IN (SELECT student_id FROM score,(SELECT course_id,MAX(num) 最大值 FROM score WHERE course_id in (SELECT cid FROM course WHERE teacher_id=(SELECT teacher_id FROM course GROUP BY teacher_id ORDER BY COUNT(cid) DESC LIMIT 1)) GROUP BY course_id HAVING max(num)) A WHERE A.最大值=score.num AND score.course_id=A.course_id);

  • 相关阅读:
    洛谷P1026 统计单词个数【区间dp】
    洛谷P1417 烹调方案【dp】
    ArcEngine不同种类的工作空间建立查询ICursor时“超出系统资源”
    解释器模式
    设计模式6大原则简述
    访问者模式
    享元模式
    中介者模式
    职责链模式
    GridControl/GridView的分组操作
  • 原文地址:https://www.cnblogs.com/1204guo/p/7270488.html
Copyright © 2011-2022 走看看