mysql(多表)

1外键

  定义:外键是指引用另一个表中的一列或多列,被引用的列应该具有主键约束或唯一性约束,外键用于建立和加强两个表数据之间的连接。

1.1 为表添加外键约束

语法:ALTER TABLE 表名 ADD CONSTRAINT 外键名 FOREIGN KEY(外键字段名) REFERENCES 外表表名(主键字段名);

举例:为student表添加外键约束

 

命令:ALTER TABLE student ADD CONSTRAINT FK_ID FOREIGN KEY (gid) REFERENCES grade(id);

也可以在创建表的时候为其添加外键

CREATE TABLE score (
  id INT(4) NOT NULL AUTO_INCREMENT,
  stu_number INT(4) DEFAULT NULL,
  cou_number INT(4) DEFAULT NULL,
  s_score DOUBLE DEFAULT NULL,
  
  PRIMARY KEY (id),
  CONSISTENT score_stu_number_studentnumber FOREIGN KEY(stu_number) REFERENCES student(stu_number)// score_stu_number_studentnumber 外键名
) ENGINE=INNODB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8

  操作关联表

2.1 关联关系

(1)多对一

 数据表中最常见的一种关系,比如学生与班级的关系,一个班级可以有多个学生,但是一个学生不能属于多个班级。在多对一的关系中,应该将外键建在多的一方。

课程和老师表 (假定一门课程多个老师  ,一个老师一门课程)

(2)多对多(多对多应该提供第三张表存放这两者的关系)

比如学生与课程的关系,一个学生可以选择多门课程,一门课程也供多个学生选择

第三张表  用于存放学生和课程之间的关系

(3)一对一(外键可以在任意一方)

比如一个人只有一张身份证,而一张身份证也只对应一个人。

 

3、连接查询

(1)内链接

内连接(Inner Join)又称简单连接或自然连接,是一种常见的连接查询。内连接使用比较运算符对两个表中的数据进行比较,并列出与连接条件匹配的数据行,组成新的记录。

语法:SELECT 查询字段 FROM 表1 [ INNER ] JOIN 表2 ON 表1.关系字段=表2.关系字段

 

其中 INNER JOIN 用于连接两个表,ON 来指定连接条件  inner可以省略

/*1 查询"01"课程比"02"课程成绩高的学生的信息及课程分数*/
	SELECT 
	   s.s_number, s.s_name NAME,s.s_age age, s.s_gender gender, sc.s_score AS '01成绩', sc2.s_score AS '02成绩'
	 FROM student s
	  JOIN score sc
	 
	 ON s.s_number=sc.stu_number AND sc.cou_number='01'
	
	  JOIN score sc2
	 ON  s.s_number=sc2.stu_number AND sc2.cou_number='02'
	
	WHERE  sc.s_score >sc2.s_score ;

(2)  自连接

 如果在一个连接查询中涉及的两个表其实是同一个表,这种查询称为自连接查询,例如要查询王红所在的部门有多少个人,就可以用自连接查询。

命令:SELECT p1.*  FROM employee AS p1 JOIN employee AS p2 ON p1.did=p2.did WHERE p2.name='王红';

 

(3)外连接分为左连接和右连接,当返回的查询结果不仅需要包含符合条件的数据,还需要包含其中一个表或者两个表的所有数据的时候,需要用到外连接查询。(左外连接  左边表全部显示,右外连接则右边表全部显示   ,左右外连接可以通过互换位置和相应的left  /outer 达到相同的结果)

语法:SELECT 所查字段 FROM 表1 LEFT | RIGHT [ OUTER ] JOIN 表2

   ON 表1.关系字段=表2.关系字段 

 

   WHERE 条件

4、子查询

 子查询是指一个查询语句嵌套在另一个查询语句内部的查询。在执行时,首先执行子查询中的语句,然后将返回的结果作为外层查询的过滤条件。

4.1  带 IN 关键字的子查询(in  先执行里面的查询  SELECT did FROM  employee WHERE age=20

举例1:查询年龄为20岁的员工的部门

命令:SELECT * FROM department WHERE id IN (SELECT did FROM  employee WHERE age=20);

 

 

4.2  带 EXISTS 关键字的子查询

 EXISTS 关键字后面的参数可以是任意一个子查询,这个子查询不产生任何数据,只返回 TRUE 或 FALSE,当返回 TRUE 时,外层查询才会执行。

举例:查询employee表中是否存在年龄大于21岁的员工,若存在则查询department表中所有记录。

命令:SELECT * FROM department WHERE EXISTS (SELECT did FROM employee WHERE age >21 );

 

4.3  带 ANY 关键字的子查询()

 ANY 关键字表示只要满足内层子查询中的任意一个条件,就返回一个结果作为外层查询条件。

举例:使用带ANY 关键字的查询,查询满足条件的部门。

命令:SELECT * FROM department WHERE did >ANY (SELECT did FROM employee);

 

在此命令中,子查询会先将employee表中所有did查询出来,分别是1,1,2,4,然后将 department 中的 did 的值与之比较,只要大于employee.did中的任意一个值,就是符合查询条件的结果。由于employee.did的最小值为1,所以department中只要大于1的did都满足条件,即2,3,5。

 

4.4  带 ALL 关键字的子查询

ALL关键字类似于ANY ,只是ALL关键字的子查询返回的结果需要同时满足所有内查询条件。

举例:使用带 ALL 关键字的子查询,查询满足条件的部门。

命令:SELECT * FROM department WHERE did > ALL (SELECT did FROM employee);

5.5  带 比较运算符的子查询

举例:使用带比较运算符的子查询,查询赵四属于哪个部门

命令:SELECT did,name FROM department WHERE did = (SELECT did FROM employee WHERE name='赵四');

CASE命令有两种语句格式:
语法形式1:CASE expression
            WHEN expression_11 THEN expression_12
             …
            WHEN expression_n1 THEN expression_n2
            [ELSE expression_m]
            END
该语句的执行过程是:将CASE后面表达式的值与各WHEN子句中的表达式的值进行比较,如果两者相等,则返回THEN后的表达式的值,然后跳出CASE语句,否则返回ELSE子句中的表达式的值。ELSE子句是可选项。当CASE语句中不包含ELSE子句时,如果所有比较失败时,CASE语句将返回NULL。
【例】从数据表stud_info中,选取stud_id、grade,如果grade为“男”则输出“M”,如果为“女”输出“F”。
SELECT stud_id, sex=CASE gender
                      WHEN ’男’ THEN ’M’
                      WHEN ’女’ THEN ’F’
                    END
FROM stud_info


语法形式2:CASE WHEN condition_expression_1 THEN expression_1
              …
             WHEN condition_expression_n THEN expression_n
             [ELSE expression_m]
           END
该语句的执行过程是:首先测试WHEN后的条件表达式的值,如果其值为真,则返回THEN后面的表达式的值,否则测试下一个WHEN子句中的表达式的值,如果所有WHEN子句后的表达式的值都为假,则返回ELSE后的表达式的值,如果在CASE语句中没有ELSE子句,则CASE表达式返回NULL。
注意:CASE命令可以嵌套到SQL语句中。

【例】从stud_grade表中查询所有同学考试成绩情况,凡成绩为空者输出“未考”、小于60分输出“不及格”、60分至70分输出“及格”、70分至90分输出“良好”、大于或等于90分时输出“优秀”。
SELECT stud_id,name,score=CASE WHEN grade IS NULL THEN ’未考’
                              WHEN grade<60 THEN ’不及格’
                              WHEN grade>=60 AND grade<70 THEN ’及格’
                              WHEN grade>=70 AND grade<90 THEN ’良好’
                              WHEN grade>=90 THEN ’优秀’
                         END
FROM stud_grade

练习:

--1.学生表
Student   -学生编号,s_name 学生姓名,s_age 出生年月,s_gender 学生性别
--2.课程表 
course  - --课程编号,c_name 课程名称,c_teachername 教师编号
--3.教师表 
teacher       t_number教师编号,t_name 教师姓名
--4.成绩表 
score --   id ,stu_number学生编号,cou_number 课程编号,score 分数
*/

创建表:

DROP TABLE IF EXISTS student;
CREATE TABLE student (
  s_number INT(4) NOT NULL AUTO_INCREMENT,
  s_name VARCHAR(20) DEFAULT NULL,
  s_age DATE DEFAULT NULL,
  s_gender CHAR(2) DEFAULT NULL,
  PRIMARY KEY (s_number)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

CREATE TABLE teacher (
  t_number INT(4) NOT NULL AUTO_INCREMENT,
  t_name VARCHAR(20) DEFAULT NULL,
  PRIMARY KEY (`t_number`)
) ENGINE=INNODB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8

CREATE TABLE score (
  id INT(4) NOT NULL AUTO_INCREMENT,
  stu_number INT(4) DEFAULT NULL,
  cou_number INT(4) DEFAULT NULL,
  s_score DOUBLE DEFAULT NULL,
  
  PRIMARY KEY (id),
  CONSISTENT score_stu_number_studentnumber FOREIGN KEY(stu_number) REFERENCES student(stu_number)
) ENGINE=INNODB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8

CREATE TABLE course (
  c_number INT(4) NOT NULL AUTO_INCREMENT,
  c_name VARCHAR(20) DEFAULT NULL,
  c_teachernumber INT(4) NOT NULL,
  PRIMARY KEY (c_number)
  
) ENGINE=INNODB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8

  数据:

INSERT INTO student VALUES('01' , '赵雷' , '1990-01-01' , '男');
INSERT INTO student VALUES('02' , '钱电' , '1990-12-21' , '男');
INSERT INTO student VALUES('03' , '孙风' , '1990-05-20' , '男');
INSERT INTO student VALUES('04' , '李云' , '1990-08-06' , '男');
INSERT INTO student VALUES('05' , '周梅' , '1991-12-01' , '女');
INSERT INTO student VALUES('06' , '吴兰' , '1992-03-01' , '女');
INSERT INTO student VALUES('07' , '郑竹' , '1989-07-01' , '女');
INSERT INTO student VALUES('08' , '王菊' , '1990-01-20' , '女');

INSERT INTO course VALUES('01' , '语文' , '02');
INSERT INTO course VALUES('02' , '数学' , '01');
INSERT INTO course VALUES('03' , '英语' , '03');

INSERT INTO teacher VALUES('01' , '张三');
INSERT INTO teacher VALUES('02' , '李四');
INSERT INTO teacher VALUES('03' , '王五');

INSERT INTO score VALUES(NULL,'01' , '01' , 80);
INSERT INTO score VALUES(NULL,'01' , '02' , 90);
INSERT INTO score VALUES(NULL,'01' , '03' , 99);
INSERT INTO score VALUES(NULL,'02' , '01' , 70);
INSERT INTO score VALUES(NULL,'02' , '02' , 60);
INSERT INTO score VALUES(NULL,'02' , '03' , 80);
INSERT INTO score VALUES(NULL,'03' , '01' , 80);
INSERT INTO score VALUES(NULL,'03' , '02' , 80);
INSERT INTO score VALUES(NULL,'03' , '03' , 80);
INSERT INTO score VALUES(NULL,'04' , '01' , 50);
INSERT INTO score VALUES(NULL,'04' , '02' , 30);
INSERT INTO score VALUES(NULL,'04' , '03' , 20);
INSERT INTO score VALUES(NULL,'05' , '01' , 76);
INSERT INTO score VALUES(NULL,'05' , '02' , 87);
INSERT INTO score VALUES(NULL,'06' , '01' , 31);
INSERT INTO score VALUES(NULL,'06' , '03' , 34);
INSERT INTO score VALUES(NULL,'07' , '02' , 89);
INSERT INTO score VALUES(NULL,'07' , '03' , 98);

  操作:

/*1 查询"01"课程比"02"课程成绩高的学生的信息及课程分数*/
	SELECT 
	   s.s_number, s.s_name NAME,s.s_age age, s.s_gender gender, sc.s_score AS '01成绩', sc2.s_score AS '02成绩'
	 FROM student s
	  JOIN score sc
	 
	 ON s.s_number=sc.stu_number AND sc.cou_number='01'
	
	  JOIN score sc2
	 ON  s.s_number=sc2.stu_number AND sc2.cou_number='02'
	
	WHERE  sc.s_score >sc2.s_score ;

 过程   (1)先执行

SELECT 
s.s_number, s.s_name NAME,s.s_age age, s.s_gender gender, sc.s_score AS '01成绩'
FROM student s
JOIN score sc

ON s.s_number=sc.stu_number AND sc.cou_number='01'

得到:

   

(2 )将得到的结果表再join score sc2  加上条件

sc2

得到最终结果:

/*2 查询"01"课程比"02"课程成绩低的学生的信息及课程分数*/

	SELECT s.* ,sc.s_score AS '01课程',sc2.s_score AS '02课程'
	 
	FROM  student s
	JOIN  score sc
	ON sc.stu_number=s.s_number AND sc.cou_number='01'
	JOIN score sc2
	ON sc2.stu_number=s.s_number AND sc2.cou_number='02'
	WHERE sc2.s_score>sc.s_score;

  

/*3 查询平均成绩大于等于60分的同学的学生编号和学生姓名和平均成绩*/


/*(1)求所有同学的平均成绩*/
	SELECT s.*, AVG(s_score) AS AVG 
		FROM score  s
		GROUP BY stu_number





  (2)

SELECT s.s_number,s.s_name,t.AVG
	FROM student s
	JOIN (SELECT s.*, AVG(s_score) AS AVG 
		FROM score  s
		GROUP BY stu_number) t
	ON t.stu_number=s.s_number AND t.AVG>=60

  

/*4 查询平均成绩小于80分的同学的学生编号和学生姓名和平均成绩*/
	SELECT student.s_name,student.s_number,t.平均成绩
	FROM student
	
	JOIN (SELECT sc.stu_number,AVG(sc.s_score) AS '平均成绩'
	FROM score sc
	GROUP BY stu_number) t
	ON t.stu_number=student.s_number 
	WHERE t.平均成绩<80

  

/*5 查询所有同学的学生编号、学生姓名、选课总数、所有课程的总成绩*/
  a 选课总数:
    

    SELECT stu_number,COUNT(*)
    FROM score
    GROUP BY stu_number

 

SELECT s.s_number,s.s_name,t.xkzs,f.zcj/*总成绩*/
	FROM student s
	JOIN (SELECT stu_number,COUNT(*)  AS 'xkzs'  /*选课总数*/
	FROM score
	GROUP BY stu_number) t
	ON t.stu_number=s.s_number
	JOIN  (SELECT stu_number,SUM(s_score) AS 'zcj' FROM score GROUP BY  stu_number) f
	ON f.stu_number=s.s_number

  

/*6、查询"李"姓老师的数量 */
    SELECT * FROM teacher;
    SELECT COUNT(*) FROM teacher WHERE t_name LIKE '李%';

/*7、查询学过"张三"老师授课的同学的信息 */
    (1) 找到张三老师对应的课程编号(因为在score表中没有教师编号 只有课程编号 所以先找到对应的课程编号) SELECT c.c_teacherNumber AS t_num,c.c_number ,t.t_name FROM course c JOIN teacher t ON t.t_number=c.c_teacherNumber AND t.t_name='张三'

  (2)将刚查出来的表join score  找到对应的student的编号

		SELECT stu_number ,f.t_name,f.t_num
		FROM score sc
		JOIN (SELECT c.c_teacherNumber AS t_num,c.c_number ,t.t_name
		
			FROM course c
			JOIN  teacher t
			ON t.t_number=c.c_teacherNumber AND t.t_name='张三') f
		ON f.c_number=sc.cou_number
	

  (3) 根据匹配的student的number 找到student的信息

SELECT  s.*, l.t_name,l.t_num
		FROM student s
		JOIN (SELECT stu_number ,f.t_name,f.t_num
		FROM score sc
		JOIN (SELECT c.c_teacherNumber AS t_num,c.c_number ,t.t_name
		
				FROM course c
				JOIN  teacher t
				ON t.t_number=c.c_teacherNumber AND t.t_name='张三') f
			ON f.c_number=sc.cou_number) l
		
		ON l.stu_number =s.s_number

 

在下面的表中你可以看到只有id=6的学生没有选课程编号为2的课程  即没有选‘张三老师的课’

/*8、查询没学过"张三"老师授课的同学的信息 */

  (1)先找到学过张三老师课程的学生的stu_number

SELECT stu_number ,f.t_name,f.t_num
		FROM score sc
		JOIN (SELECT c.c_teacherNumber AS t_num,c.c_number ,t.t_name
		
			FROM course c
			JOIN  teacher t
			ON t.t_number=c.c_teacherNumber AND t.t_name='张三') f
		ON f.c_number=sc.cou_number

  

(2)用not  in()

  

SELECT * FROM student WHERE  s_number NOT IN(SELECT stu_number
		FROM score sc
		JOIN (SELECT c.c_teacherNumber AS t_num,c.c_number ,t.t_name
		
			FROM course c
			JOIN  teacher t
			ON t.t_number=c.c_teacherNumber AND t.t_name='张三') f
		ON f.c_number=sc.cou_number)

      8号没有选课   所以没有他的选课记录(因此在not  in中显示出来)

/*9、查询学过编号为"01"并且也学过编号为"02"的课程的同学的信息*/
	《1》SELECT  ss.stu_number
		FROM score ss
		JOIN (SELECT  stu_number ,cou_number
			FROM score
			WHERE cou_number='02') t
		ON t.stu_number=ss.stu_number AND ss.cou_number='01'
		
		
		
		
		
		《2》SELECT  s.stu_number
		FROM  score s
		JOIN score ss
		ON s.stu_number=ss.stu_number AND s.cou_number='01' AND ss.cou_number='02';
		  

  两种写法结果都一样   都是现实两种编号课程都学习了得学生的编号

在将(学生编号在这个表中的数据)展示出来。(自连接)

		SELECT * FROM student WHERE  s_number IN(
		SELECT  s.stu_number
		FROM  score s
		JOIN score ss
		ON s.stu_number=ss.stu_number AND s.cou_number='01' AND ss.cou_number='02');

  

/*10、查询学过编号为"01"但是没有学过编号为"02"的课程的同学的信息*/
		SELECT *

			FROM student a

			LEFT JOIN score b

			ON a.s_number=b.stu_number AND b.cou_number='01'
			LEFT JOIN score c

			ON a.s_number=c.stu_number AND c.cou_number='02'

  

将 c表中的不是null的项去除

	SELECT a.*

			FROM student a

			LEFT JOIN score b

			ON a.s_number=b.stu_number AND b.cou_number='01'
			LEFT JOIN score c

			ON a.s_number=c.stu_number AND c.cou_number='02'
			WHERE 
				b.cou_number='01'AND c.cou_number IS NULL 

  


/*-11、查询学全所有课程的同学的信息 */

SELECT * FROM student WHERE s_number IN( SELECT stu_number FROM score GROUP BY stu_number HAVING COUNT(*) = (SELECT COUNT(*) FROM course));

原文地址:https://www.cnblogs.com/MyJavaStudy/p/9182888.html