1. 概述
项目开发中,在进行数据库表结构设计时,会根据业务需求及业务模块之间的关系,分析并设计表结构,由于
业务之间相互关联,所以各个表结构之间也存在着各种联系,基本上分为三种:
- 一对多(多对一)
- 多对多
- 一对一
1.1 一对多(多对一)
案例:
部门与员工的关系
关系:
一个部分对应多个员工,一个员工对应一个部分
实现:
在多的一方建立外键,指向一的一方的主键
1.2 多对多
案例:
学生与课程的关系
关系:
一个学生可以选择多门课程,一门课程也可以供多个学生选择
实现:
建立第三张中间表,中间表至少包含两个外键,分别关联两方主键
相关示例建表语句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | CREATE TABLE student( id INT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID' , name VARCHAR (10) COMMENT '姓名' , no VARCHAR (10) COMMENT '学号' )COMMENT '学生表' ; INSERT INTO student VALUES ( null , '黛绮丝' , '2000100101' ),( null , '谢逊' , '2000100102' ),( null , '殷天正' , '2000100103' ),( null , '韦一笑' , '2000100104' ); CREATE TABLE course( id INT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID' , name VARCHAR (10) COMMENT '课程名称' ); INSERT INTO course VALUES ( null , 'java' ),( null , 'php' ),( null , 'MySQL' ),( null , 'hadoop' ); CREATE TABLE student_course( id INT AUTO_INCREMENT PRIMARY KEY COMMENT '主键' , studentid INT NOT NULL COMMENT '学生ID' , courseid INT NOT NULL COMMENT '课程ID' , CONSTRAINT FK_COURSEID FOREIGN KEY (courseid) REFERENCES course(id), CONSTRAINT FK_STUDENTID FOREIGN KEY (studentid) REFERENCES student(id) )COMMENT '学生课程中间表' ; |
1.3 一对一
案例:
用户与用户详情的关系
关系:
一对一关系,多用于单表拆分,将一张表的基础字段放在一张表中,其他详情字段放在另一张表中,以提升操作效率
实现:
在任意一方加入外键,关联另外一方的主键,并且设置外键为唯一的(UNIQUE)
相关示例建表语句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | CREATE TABLE tb_user( id INT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID' , name VARCHAR (10) COMMENT '姓名' , age INT COMMENT '年龄' , gender CHAR (1) COMMENT '1:男,2:女' , phone CHAR (11) COMMENT '手机号' ) COMMENT '用户基本信息表' ; CREATE TABLE tb_user_edu( id INT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID' , degree VARCHAR (20) COMMENT '学历' , major VARCHAR (50) COMMENT '专业' , primaryschool VARCHAR (50) COMMENT '小学' , minddleschool VARCHAR (50) COMMENT '中学' , university VARCHAR (50) COMMENT '大学' , userid INT UNIQUE COMMENT '用户ID' , CONSTRAINT FK_USERID FOREIGN KEY (userid) REFERENCES tb_user(id) )COMMENT '用户教育信息表' ; INSERT INTO tb_user(id, name , age, gender, phone) VALUES ( null , '黄渤' ,45, '1' , '1880001111' ), ( null , '冰冰' ,35, '2' , '1880002222' ), ( null , '码云' ,55, '1' , '1880008888' ), ( null , '李彦宏' ,50, '1' , '1880009999' ); INSERT INTO tb_user_edu(id, degree, major, primaryschool, minddleschool, university, userid) VALUES ( null , '本科' , '舞蹈' , '静安区第一小学' , '静安区第一中学' , '北京舞蹈学院' , '1' ), ( null , '硕士' , '表演' , '朝阳区第一小学' , '朝阳区第一中学' , '北京电影学院' , '2' ), ( null , '本科' , '英语' , '杭州市第一小学' , '杭州市第一中学' , '杭州师范大学' , '3' ), ( null , '本科' , '应用数学' , '阳泉第一小学' , '阳泉区第一中学' , '清华大学' , '4' ); |
2. 多表查询概述
2.1 概述
指从多张表中查询数据
2.2 笛卡尔积
笛卡尔乘积是指在数学中,两个集合A集合和B集合的所有组合情况。(在多表查询时,需要消除无效的笛卡尔积)
2.3 多表查询
连接查询
内连接:
相当于查询A、B交集部分数据
外连接:
左外连接: 查询左表所有数据,以及两张表交集部分数据
右外连接: 查询右表所有数据,以及两张表交集部分数据
自连接:
当前表与自身的连接查询,自连接必须使用表别名
子查询
2.3.1 内连接
查询语法
1 2 3 4 | -- 隐式内连接 SELECT 字段列表 FROM 表1,表2 WHERE 条件...; -- 显式内连接 SELECT 字段列表 FROM 表1 [ INNER ] JOIN 表2 ON 连接条件...; |
说明:
内连接查询的是两张表交集的部分
内连接演示
1 2 3 4 5 | -- 1. 查询每一个员工的姓名,及关联的部门的名称(隐式内连接实现) SELECT employee. name ,dept. name FROM employee,dept WHERE employee.dept_id = dept.id; SELECT e. name ,d. name FROM employee e,dept d WHERE e.dept_id = d.id; -- 2. 查询每一个员工的姓名,及关联的部门的名称(显式内连接实现) SELECT e. name ,d. name FROM employee e INNER JOIN dept d ON e.dept_id = d.id |
2.3.2 外连接
查询语法
1 2 3 4 5 | -- 左外连接 SELECT 字段列表 FROM 表1 LEFT [ OUTER ] JOIN 表2 ON 条件; -- 相当于查询表1(左表)的所有数据包含表1和表2的交集部分的数据 -- 右外连接 SELECT 字段列表 FROM 表1 RIGHT [ OUTER ] JOIN 表2 ON 条件;<br> -- 对于union查询,就是把多次查询的结果合并起来,形成一个新的查询结果集。 |
外连接演示
1 2 3 4 | -- 1. 查询employee表的所有数据,和对应的部门信息(左外连接) SELECT e.*,d. name FROM employee e LEFT OUTER JOIN dept d ON e.dept_id = d.id; -- 2. 查询dept表的所有数据,和对应的员工信息(右外连接) SELECT d.*,e.* FROM employee.e RIGHT OUTER JOIN dept d ON e.dept_id = d.id; |
2.3.3 自连接
查询语法
1 | SELECT 字段列表 FROM 表A 别名A JOIN 表A 别名B ON 条件...; |
说明:
自连接查询,可以是内连接查询,也可以是外连接查询。
自连接演示
1 2 3 4 | -- 1. 查询员工及其所属领导的名字 SELECT a. name ,b. name FROM employee a,employee b WHERE a.managerid = b.id; -- 2. 查询所有员工及其领导的名字,如果员工没有领导,也需要查询出来 SELECT a. name ,b. name FROM employee a LEFT JOIN employee b ON a.managerid = b.id; |
2.3.4 联合查询-union,union all
对于union查询,就是把多次查询的结果合并起来,形成一个新的查询结果集。
查询语法
1 2 3 | SELECT 字段列表 FROM 表A ... UNION [ ALL ] SELECT 字段了表 FROM 表B ...; |
注意:
- 对于联合查询的多张表的列数必须保持一致,字段类型也需要保持一致。
- UNION ALL 会将全部的数据直接合并在一起,UNION会对合并之后的数据去重。
联合查询演示
1 2 3 4 | -- 1. 将薪资低于5000的员工和年龄大于50岁的员工全部查询出来。 SELECT * FROM employee WHERE salary < 5000 UNION ALL SELECT * FROM employee WHERE age > 50; |
2.3.5 子查询
概念:
SQL 语句中嵌套SELECT语句,称为嵌套查询,又称子查询。
语法:
1 | SELECT * FROM t1 WHERE column1 = ( SELECT column1 FROM t2); |
说明:
子查询外部的语句可以是INSERT/UPDATE/DELETE/SELECT的任何一个
根据子查询结果不同,分为:
- 标量子查询(子查询结果为单个值)
- 列子查询(子查询结果为一列)
- 行子查询(子查询结果为一行)
- 表子查询(子查询结果为多行多列)
根据子查询位置,分为WHERE之后,FROM之后,SELECT之后。
2.3.5.1 标量子查询
子查询返回的结果是单个值(数字,字符串,日期等),最简单的形式,这种子查询称为标量子查询。
常用的操作符: = <> > >= < <=
标量子查询演示
1 2 3 4 | -- 1. 查询"销售部"的所有员工信息 SELECT * FROM employee WHERE dept_id = ( SELECT id FROM dept WHERE name = '销售部' ); -- 2. 查询"方东白"入职之后的员工信息 SELECT * FROM employee WHERE entrydate > ( SELECT entrydate FROM employee WHERE name LIKE '方东白' ); |
2.3.5.2 列子查询
子查询返回的结果是一列(可以多行),这种子查询称为列子查询
常用的操作符: IN、NOT IN、ANY、SOME、ALL
列子查询演示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | -- 1. 查询'销售部'和'市场部'的所有员工信息 -- a. 查询"销售部"和"市场部"的部门ID SELECT id FROM dept WHERE name LIKE '市场部' OR name LIKE '销售部' ; -- b. 根据部门ID查询所有员工信息 SELECT * FROM employee WHERE dept_id in (2,4); SELECT * FROM employee WHERE dept_id in ( SELECT id FROM dept WHERE name LIKE '市场部' OR name LIKE '销售部' ); -- 2. 查询比财务部所有人工资都高的员工信息 -- a. 查询财务部所有人的工资 SELECT id FROM dept WHERE name LIKE '财务部' ; SELECT salary FROM employee WHERE dept_id = ( SELECT id FROM dept WHERE name LIKE '财务部' ); -- b. 比财务部所有人工资都高的员工信息 SELECT * FROM employee WHERE salary > all ( SELECT salary FROM employee WHERE dept_id = ( SELECT id FROM dept WHERE name LIKE '财务部' )); -- 3. 查询比研发部其中任意一人工资高的员工信息 -- a. 查询研发部所有人的薪资 SELECT id FROM dept WHERE name LIKE '研发部' ; SELECT salary FROM employee WHERE dept_id = ( SELECT id FROM dept WHERE name LIKE '研发部' ); -- b. 比研发部任意一人薪资高的员工信息 SELECT * FROM employee WHERE salary > SOME ( SELECT salary FROM employee WHERE dept_id = ( SELECT id FROM dept WHERE name LIKE '研发部' )); |
2.3.5.3 行子查询
子查询返回的结果就是一行(可以是多列),这种子查询称为行子查询
常用的操作符: = 、<> 、IN 、NOT IN
行子查询演示
1 2 3 4 5 | -- 1. 查询与"张无忌"的薪资及直属领导相同的员工信息; -- a. 查询"张无忌"的薪资及直属领导 SELECT salary,managerid FROM employee WHERE name LIKE '张无忌' ; -- b. 查询与"张无忌"的薪资及直属领导相同的员工信息; SELECT * FROM employee WHERE (salary,managerid) = ( SELECT salary,managerid FROM employee WHERE name LIKE '张无忌' ); |
2.3.5.4 表子查询
子查询返回的结果的是多行多列,这种子查询称为表子查询
常用操作符: IN
表子查询演示
1 2 3 4 5 6 7 8 9 10 | -- 1. 查询与"鹿杖客","宋远桥"的职位和薪资相同的员工信息 -- a. 查询"鹿杖客","宋远桥"的职位和薪资 SELECT salary,job FROM employee WHERE name LIKE '宋远桥' OR name LIKE '鹿杖客' ; -- b. 查询与"鹿杖客","宋远桥"的职位和薪资相同的员工信息 SELECT * FROM employee WHERE (salary,job) IN ( SELECT salary,job FROM employee WHERE name LIKE '宋远桥' OR name LIKE '鹿杖客' ); -- 2. 查询入职是"2006-01-01"之后的员工信息,及其部门信息 -- a. 入职日期是"2006-01-01"之后的员工信息,及其部门信息 SELECT * FROM employee WHERE entrydate > '2006-01-01' ; -- b. 查询这部分员工,对应的部门信息 SELECT e.*,d.* FROM ( SELECT * FROM employee WHERE entrydate > '2006-01-01' ) e LEFT JOIN dept d on e.dept_id = d.id; |
3 多表查询案例
准备环境SQL
1 2 3 4 5 6 7 8 9 10 11 | CREATE TABLE salgrade( grade int , losal int , hisal int )COMMENT '薪资等级表' ; INSERT INTO salgrade VALUES (1,0,3000),(2,3001,5000), (3,5001,8000),(4,8001,10000), (5,10001,15000),(6,15001,20000), (7,20001,25000),(8,25001,30000); |
根据需求,完成SQL语句的编写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | -- 1、查询员工的姓名、年龄、职位、部门信息。(隐式内连接) -- 表: employee,dept -- 连接条件: employee.dept_id = dept.id SELECT e. name ,e.age,e.job,d. name FROM employee e , dept d WHERE e.dept_id = d.id; -- 2、查询年龄小于30岁的员工姓名、年龄、职位、部门信息。(显示内连接) -- 表: employee,dept -- 连接条件: employee.dept_id = dept.id SELECT e. name ,e.age,e.job,d. name FROM ( SELECT * FROM employee WHERE age < 30) e INNER JOIN dept d ON e.dept_id = d.id; select e. name ,e.age,e.job,d. name FROM employee e INNER JOIN dept d on e.dept_id = d.id WHERE e.age < 30; -- 3、查询拥有员工的部门ID、部门名称。 -- 表: employee,dept -- 连接条件: employee.dept_id = dept.id SELECT DISTINCT d.id,d. name FROM employee e,dept d WHERE e.dept_id = d.id; -- 4、查询所有年龄大于40的员工,及其归属的部门名称;如果员工没有分配部门,也要展示出来。 -- 表: employee,dept -- 连接条件: employee.dept_id = dept.id -- 外连接 SELECT e. name ,d. name FROM employee e LEFT JOIN dept d on e.dept_id = d.id WHERE e.age > 40; -- 5、查询所有员工的工资等级。 -- 表: employee,salgrade -- 连接条件: employee.salary between salgrade.losal and salgrade.hisal SELECT e.*,s.* FROM employee e,salgrade s WHERE e.salary between s.losal and s.hisal; -- 6、查询"研发部"所有员工的信息及工资等级。 -- 表: employee,salgrade,dept -- 连接条件: employee.salary between salgrade.losal and salgrade.hisal , employee.dept_id = dept.id -- 查询条件: dept.name = '研发部' SELECT e.*,s.grade FROM employee e,salgrade s,dept d WHERE e.dept_id = d.id and (e.salary between s.losal and s.hisal) and d. name = '研发部' ; -- 7、查询"研发部"员工的平均工资。 -- 表: employee,dept -- 连接条件: employee.dept_id = dept.id -- 查询条件: dept.name = '研发部' -- 函数: AVG SELECT AVG (e.salary) FROM employee e , dept d WHERE e.dept_id = d.id and d. name LIKE '研发部' ; -- 8、查询工资比"灭绝"高的员工信息。 -- a. 查询"灭绝"的工资 SELECT salary FROM employee WHERE name LIKE '灭绝' ; -- b. 比灭绝高的薪资 select * FROM employee WHERE salary > ( SELECT salary FROM employee WHERE name LIKE '灭绝' ); -- 9、查询比平均薪资高的员工信息。 -- a. 查询所有员工的平均薪资 SELECT AVG (salary) FROM employee; -- b. 比平均工资高的员工信息 select * FROM employee WHERE salary > ( SELECT AVG (salary) FROM employee); -- 10、查询低于本部门平均工资的员工信息。 -- a. 查询指定部门平均薪资 SELECT AVG (salary) FROM employee e1 WHERE e1.dept_id = '1' ; -- b. 查询低于本部门的平均薪资的员工信息 SELECT * FROM employee e2 WHERE e2.salary < ( SELECT AVG (salary) FROM employee e1 WHERE e1.dept_id = e2.dept_id); -- 11、查询所有的部门信息,共统计部门的员工人数。 SELECT DISTINCT d.id,d. name ,( SELECT COUNT (*) FROM employee e WHERE e.dept_id = d.id) '人数' FROM dept d; -- 12、查询所有学生的选课情况,展示出学生名称,学号,课程名称。 -- 表: student , course , student_course -- 连接条件: student.id = student_course.studentid , course.id = student_course.courseid SELECT s. no ,s. name ,c. name FROM student s,course c,student_course sc WHERE s.id = sc.studentid and c.id = sc.courseid; |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
2020-02-06 nginx常用模块(一)