回顾:
SQL分类:
DDL: 数据定义语言,定义数据库/表的结构:drop,alter,create,truncate
DML: 数据操纵语言,操纵的是数据: insert ,delete, update,
DQL: 数据查询语言,查询数据:select,where,group by, having, order by
DCL: 数据控制语言,控制的权限: grant,revoke
数据库CRUD:
增加:create database 名称
删除:drop database 名称
修改:alter database 名称 character set utf8;
查询:show databases;
show create database 名称
其他: use 名称 : 选中数据库,切换数据库
表的CRUD:
增加:create table 名称(
列明 列的类型 列的约束,
列名 列的类型 列的约束
);
列的类型: int,float,double,date,datetime,timestamp,char(10)/varchar(10)
列的约束:
主键约束:primary key 唯一并且不能为空 (编号)
唯一约束:unique 唯一允许为空
非空约束:not null 不允许为空
检查约束: check msyql不支持这种约束
外键约束: foreign key 多表之间的约束
删除:drop table 名称
修改:
添加列: alter table 名称 add 列明 列的类型
重定义列: alter table 名称 modify 列名 列的类型
删除列: alter table 名称 drop 列明
修改列明: alter table 名称 change 旧列明 新列名 列的类型
修改表名: rename table 表名 to 新表名
查询:
show tables;
show create table 名称
desc 名称
表中数据的CRUD:
增加: insert into 名称(列名1,列名2) values(值1,值2)
insert into 名称 values(值1,值2);
删除: delete from 名称 【where 条件】
truncate table 名称
修改: update 名称 set 列名1=值1,列名2=值 [where 条件]
查询:
select * from 名称
select * from 名称 where 条件
select 分组的条件,分组的目标 from 表名 where 条件 group by 分组的条件 having 分之后的过滤
order by
limit
一、表关系介绍
1. 表之间为什么要有关系
一般来讲,通常都是一张表某一类型数据,比如学生数据存储在学生表,教师数据存储在教师表,学科数据存储在学科表。但是有时候我们需要表示一个学生属于哪一个班级。我们可以有两种形态表示,
一、直接在学生表里面表示属于哪一个班级。(@1) 如果我们还想表示班级更多的信息。 class表。
二、学生表表示学生信息,班级表表示班级信息,然后让学生表和班级表存在关系引用即可。
从扩展角度来看,应该是第二种方式更优秀一点,因为如果我们要扩展班级的信息,比如,位于哪个教室,班主任是谁等等信息 ,第一种方式就显得捉襟见肘,如果都把这些要扩展的信息声明在学生表里面,就打破了数据的完整性。
- 图1
- 图2
2. 表关系维系的点
一般数据表就表示某一种类型的数据。比如: 学生表、班级表。如果要让两张表存在关系,必须得有维系关系的点存在。就好比生活中怎么表示对面这位美女就是你的夫人呢?把结婚证拿出来一摆就可以了。
数据库表形成关系,并不需要额外的第三方物件来表示。只要某一张表中的某一列存放的是另一张表的一个标识即可(一般是主键id。) , 如下图表示一个学生是哪一个班级的。则需要在学生表中使用一个列cid 来存储班级的id值。 以后查询学生信息的时候,即可知道它属于的班级id。
当某一列中存放的值是另一个表的主键值,那么这个列一般会称之为外键
如:学生表的 cid列
, 所以一般表的关系,我们也可以看成是主外键关系。
一旦形成主外键关系,那么外键里面的值只能是主键值,否则就无法形成主外键关系了。如:我们在cid中写了100这个数字,这就表示必须存在编号为100的班级,否则该学生的数据就是无效的数据。一般会称外键方为从表,主键方为主表
- 思维拓展
表示学生属于哪一个班级,就在学生表里面增加一个列cid , 然后cid 就存放班级表的id值。 已上图距离, 张三就属于三年二班的学生
如果要表示这个班级有哪些学生,我们如何在班级表这边体现呢? 从群体关系上看,班级只有一个,学生有很多个。在班级里面体现学生是很难的。假如一个班有100个学生,那么班级表真的很难记住这100个学生的信息。我们只有在学生的这边记住,它属于哪一个班级。 基本上这和我们日常生活是一样的。只有多的一边记住多的一边, 一的那边很少记住多的一边。如: 我们都知道高中校长、大学校长。但是校长就很难记住我们…
要记住一个核心点: 就是在分析表关系的时候,要分清楚多的一边,和 一的一边。 然后在多的一边,建立外键,然后指向一的那一边的主键值。
3. 表关系分类
表关系的分类主要体现以下几种:
一对多
|多对一
、多对多
、一对一
。表关系是数据库操作中高阶的知识,开发中经常会碰到。
- 一对多 | 多对一
在生活中体现的有,商品分类 和 商品的关系 ,班级和学生的关系 , 教练和队员的关系… 其实
一对多
的关系反向过来是多对一
,所以平常也有可能听到多对一这样的关系,其实也是成立的。只不过是谁在前,谁在后而已。
- 多对多【拆解成两个一对多】
多对多,其实就是两个一对多组合一起。生活中最能体现这个就是学生选课这个事情了。 A 这个课程有 多个学生选择, 一个学生也可以选择多们课程。 学生选课的关系: 一个学生可以选择多门课程 ,一门课程也可以被多个学生选。
- 一对一【比较少见】
一对一的关系生活中体现比较少,除了那种一对一辅导、保姆专人照顾婴儿之外,貌似就比较少…
4. 一对多关系
此处使用商品分类 & 商品来体现一对多关系
-- 分类表
CREATE TABLE category (id INT PRIMARY KEY AUTO_INCREMENT , NAME VARCHAR(20) );
-- 商品表
CREATE TABLE product (id INT PRIMARY KEY AUTO_INCREMENT , NAME VARCHAR(20) , price DOUBLE);
-- 添加外键字段,意思是给商品添加一个额外的字段。
ALTER TABLE product ADD COLUMN cid INT ;
-- 添加额外的约束 意思是给product表添加一个外键约束
-- 约束的名称叫做product_fk 这个名字可以随便写。 外键是是cid .
-- 后面的REFERENCES 表示和哪一个表的哪一个列建立关系。
ALTER TABLE product ADD CONSTRAINT product_fk FOREIGN KEY (cid) REFERENCES category(id);
5. 多对多关系
这里使用学生选课的情形来描述 ,但是多对多比以前的一对多 或者 多对一稍显复杂些。 一般多对多都会使用第三张表来周转,把多对多变成两个一对多的关系。
-- 创建学生表
CREATE TABLE student(id INT PRIMARY KEY AUTO_INCREMENT , NAME VARCHAR(20));
-- 创建课程表
CREATE TABLE course (id INT PRIMARY KEY AUTO_INCREMENT , NAME VARCHAR(20));
-- 创建中间表 中间表独立使用没有任何意义,它得配合其他的两张表来使用才能体现出来。所以
-- 该表可以没有主键。当然假如主键也没有什么问题
CREATE TABLE stu_course(sid INT, cid INT);
-- 创建学生表和中间表的关系。 原则上学生表和课程是多对多的关系,一个学生可以选择多门课程 , 那么学生和
-- 中间选课记录表的关系应该是一对多的关系。 那么记录表作为多的一方,需要去记住一的一方
ALTER TABLE stu_course ADD CONSTRAINT stu_fk FOREIGN KEY (sid) REFERENCES student(id);
-- 添加中间表到课程表的一用。
ALTER TABLE stu_course ADD CONSTRAINT course_fk FOREIGN KEY(cid) REFERENCES course(id);
- 为什么多对多要引入中间表?
由于学生表只会存放学生信息, 课程表也只会存放课程信息。 那么要体现一个学生选择了几门课程,一门课程被多少个学生选择。 如果没有中间表,我们就需要在这两张表中各自添加额外的列来记录这些数据(如,选课的时间)。 这就使得数据表不是那么的干净。通用的做法都是采用中间表存放他们的各自关系,然后让学生表、课程表 和 中间表产生关系即可。
二、 多表查询
此前我们创建的表都是独立的表,现在表之间已经存在了联系,那么现在的查询要再上一个台阶,要使用到多表联合查询了。通俗的意思就是:查询A表 和 B表,然后才能得出一条完整的数据。 以前由于数据是独立的,所以查询A表即可得知一条完整的数据。
- 多表查询的分类
多表查询的常用手段有 :
子查询
|内连接查询
|外连接查询
1. 子查询
子查询是将一个查询语句嵌套在另外一个查询语句中,内层查询语句的查询结果,可以为外层查询语句提供查询条件 。
语法规则
- 子查询必须“自身就是一个完整的查询”。即,它必须至少包括一个SELECT子句和FROM子句。
- 子查询SELECT语句不能包括在ORDER BY子句中。因为ORDER BY字句只能对最终查询结果排序,如果显示的输出需要按照特定顺序显示,那么ORDER BY子句应该作为外部查询的最后一个子句列出。
- 子查询“必须包括在一组括号中”,以便将它与外部查询分开。
例子
-- 把商品分类为手机的所有商品给查询出来。
--1. 首先要查询出来商品分类为 【手机】 的信息。
-- 商品表里面,表示分类信息,只有一个分类id , 所以上一个步骤,要查询出来【手机】的分类id
SELECT id FROM category WHERE NAME='手机';
--2. 根据查询出来的分类id来查询所有商品。 这里使用子查询, 前面查询到的id 作为这次查询的条件。
SELECT * FROM product WHERE cid = (SELECT id FROM category WHERE NAME='手机');
2. 内连接查询
内连接查询是一种常用的连接查询,可以查询两个或两个以上的表。该查询后面必须有两张表的对等值才能成立。 如:仓库中有哪一种分类有库存的,并且列出库存商品。
内连接有两种分类:
隐式内连接
|显式内连接
- 隐式内连接
语法格式:select * from A , B where 条件 ;
这里写图片描述
-- 需求:查询商品库中,哪一种分类有商品,并且都有哪些商品。
SELECT c.name , p.name , p.price FROM category c ,product p WHERE p.cid = c.id;
- 显式内连接
语法格式:select * from A inner join B on 条件
SELECT c.name , p.name , p.price FROM category c INNER JOIN product p ON p.cid = c.id;
3. 外连接查询
外连接查询又分为
左外连接
和右外连接
1. 左外连接
以左边表为基准,查询左边表的所有数据,顺便把它里面关联的右边表数据给查询出来,即便左边表中有某些记录在右边表没有关联,那么也会查询出来,只不过关联的部分值为null而已。
使用关键字:
LEFT JOIN
或LEFT OUTER JOIN
此处以 : 列出仓库中所有分类 以及 每一种分类具体的商品信息 为例子演示 , 此处优先的是分类,所以应该以分类为基准。
-- 列出所有分类的库存情况
SELECT * FROM category c LEFT OUTER JOIN product p ON c.id = p.cid;
2. 右外连接
这和左外连接正好是反过来的,右外连接是以右边表Wie基准,查询右边表的所有数据,顺便把它关联的左边表数据也给查询出来,即便右边表的某些记录在左边表没有关联,那么也会查询出来,只不过关联部分的值为null而已。
使用关键字:
RIGHT JOIN
或RIGHT OUTER JOIN
此处以: 列出列出仓库中仍有库存的商品 以及 所属分类信息 为例子演示 , 这里的优先是有库存,所以应该以商品表为基准。
-- 列出有库存的商品,并且把分类也显示出来
SELECT * FROM category c RIGHT OUTER JOIN product p ON c.id = p.cid;
- 练习
# 查询分类为电脑的商品 -- 内连接查询
SELECT * FROM category c, product p WHERE c.name = '电脑' AND p.cid = c.id;
# 列出来所有的分类,并且显示该分类的商品 -- 左外
SELECT * FROM category c LEFT JOIN product p ON c.id = p.cid;
# 列出来库存中的所有商品,并且显示所属的分类 -- 右外
SELECT * FROM category c RIGHT JOIN product p ON c.id = p.cid;
# 列出来每一种分类有多少件商品
SELECT * FROM category c LEFT JOIN product p ON c.id =p.cid;
SELECT c.name , COUNT(*) FROM category c LEFT JOIN product p ON c.id =p.cid GROUP BY c.id;
SELECT c.name , COUNT(p.id) FROM category c LEFT JOIN product p ON c.id =p.cid GROUP BY c.id;
今日列题演练
多表之间的关系: 多张表之间的关系
多表之间的关系约束: 向A表中插入的记录,需要存在于B表中
insert into product values(null,'红牛',6,'喝了就不困了',44);
– 删除分类编号为44的记录
delete from product where cno=44;
– 多表之间的关系,由什么来维护/约束 foreign key 外键约束
– 添加一个外键约束:
– 修改 product 这张表 添加 外键约束(cno) 让它参考 category表中的cid字段
alter table product add foreign key(cno) references category(cid);
insert into product values(null,'红牛',6,'喝了就不困了',4);
/*
表的关系分类:
一对多|多对一: 商品和商品分类, 教室和学生, 教师和学生,一个爸爸和多个孩子
建表原则: 在多的一方添加一列,并且指定一个外键约束,让他指向一的一方
多对多: 学生和选课
一对一: 人和身份证号 , 公司 和 地址
*/
– 把商品分类为手机数码的所有商品给查询出来
– 连接查询
select * from category,product where category.cid = product.cno;
– 连接查询,并且限定条件
select * from category,product where category.cid = product.cno and category.cname='手机数码';
– 内连接查询 (隐式内连接) 两张表公有的数据
select * from category,product where category.cid = product.cno;
– 显式内连接
select * from category inner join product on category.cid = product.cno where category.cname='手机数码';
/*
外连接:
左外连接: 以左表为基础,查询左表中的所有数据以及右表对应的记录,若右表没有对应的记录,则显示null
left outer join ... on ..
右外连接: 以右表为基础,查询右表中所有的记录以及左表对应的记录,若左表没有对应的记录,则显示null
right outer join ... on ..
*/
– 左外连接
select * from category left outer join product on category.cid = product.cno;
– 右外连接:
insert into product values(null,'测试',190,'fasdfa',null);
select * from category right outer join product on category.cid = product.cno;
select * from product;
– 列出来每一种分类有多少件商品
– 显示所有的分类 –
select * from category left outer join product on category.cid = product.cno;
– 分组统计
select cname,COUNT(*) from category left outer join product on category.cid = product.cno group by cname;
– 列出商品分类为手机数码的所有商品
select * from product where cno = 1;
– 1.查询分类表中,手机数码的编号是多少
select cid from category where cname = '手机数码'
– 2. 子查询的结果
select * from product where cno = (select cid from category where cname = '手机数码');
/*
子查询: 查询语句中嵌套查询语句
作用: 是去解决一些复杂的查询需求
*/
– 请查询出商品表中价格最低的商品信息
select * from product;
– 1.查询最低价格是多少 5
select MIN(price) from product;
– 2. 看谁的价格等于最低价格
select * from product where price =5;
select * from product where price = (select MIN(price) from product);
/*
扩展: 子查询补充
单行子查询: 子查询出来的结果只有一行
关键字: > >= = < <= != <>
多行子查询: 子查询出来的结果有多行
关键字: in , not in , any , all
*/
create database mysqltest2;
use mysqltest2;
– 部门表
create table DEPT(
DEPTNO int primary key, – 部门编号
DNAME varchar(14) , – 部门名称
LOC varchar(13) ) ; – 部门地址
insert into DEPT values (10,’ACCOUNTING’,’NEW YORK’);
insert into DEPT values (20,’RESEARCH’,’DALLAS’);
insert into DEPT values (30,’SALES’,’CHICAGO’);
insert into DEPT values (40,’OPERATIONS’,’BOSTON’);
– 员工表
create table EMP(
EMPNO int primary key, – 员工编号
ENAME varchar(10), – 员工名称
JOB varchar(9), – 工作
MGR double, – 直属领导编号
HIREDATE date, – 入职时间
SAL double, – 工资
COMM double, – 奖金
DEPTNO int – 部门号
);
insert into EMP values
(7369,’SMITH’,’CLERK’,7902,’1980-12-17’,800,null,20);
insert into EMP values
(7499,’ALLEN’,’SALESMAN’,7698,’1981-02-20’,1600,300,30);
insert into EMP values
(7521,’WARD’,’SALESMAN’,7698,’1981-02-22’,1250,500,30);
insert into EMP values
(7566,’JONES’,’MANAGER’,7839,’1981-04-02’,2975,null,20);
insert into EMP values
(7654,’MARTIN’,’SALESMAN’,7698,’1981-09-28’,1250,1400,30);
insert into EMP values
(7698,’BLAKE’,’MANAGER’,7839,’1981-05-01’,2850,null,30);
insert into EMP values
(7782,’CLARK’,’MANAGER’,7839,’1981-06-09’,2450,null,10);
insert into EMP values
(7788,’SCOTT’,’ANALYST’,7566,’1987-07-13’,3000,null,20);
insert into EMP values
(7839,’KING’,’PRESIDENT’,null,’1981-11-17’,5000,null,10);
insert into EMP values
(7844,’TURNER’,’SALESMAN’,7698,’1981-09-08’,1500,0,30);
insert into EMP values
(7876,’ADAMS’,’CLERK’,7788,’1987-07-13’,1100,null,20);
insert into EMP values
(7900,’JAMES’,’CLERK’,7698,’1981-12-03’,950,null,30);
insert into EMP values
(7902,’FORD’,’ANALYST’,7566,’1981-12-03’,3000,null,20);
insert into EMP values
(7934,’MILLER’,’CLERK’,7782,’1982-01-23’,1300,null,10);
– 给员工表添加外键约束
alter table emp add foreign key(deptno) references dept(deptno);
– 练习
– 1.返回拥有员工的部门名、部门号。(dept,emp)
SELECT DISTINCT d.DNAME,d.DEPTNO FROM emp e,dept d WHERE d.DEPTNO=e.DEPTNO;
– 2.工资多于smith的员工信息。
一、拿到这个人的工资
SELECT SAL FROM emp WHERE ENAME="smith";
二、用所有员工的工资比对大于这个人的工资
SELECT * FROM emp WHERE SAL>(SELECT SAL FROM emp WHERE ENAME="smith")
– 所有员工的信息
select * from emp;
– 薪资大于等于1000并且小于等于2000的员工信息
select * from emp where sal between 1000 and 2000;
– 从员工表中查询出所有的部门编号
select distinct deptno from emp;
– 查询出名字以A开头的员工的信息
select * from emp where ename like 'A%';
– 查询出名字第二个字母是L的员工信息
SELECT * FROM emp WHERE ename LIKE "_L%";
– 查询出没有奖金的员工信息
SELECT * FROM emp WHERE COMM IS NULL;
– 所有员工的平均工资
SELECT AVG(SAL) FROM emp;
– 所有员工的工资总和
SELECT SUM(SAL) FROM emp;
– 所有员工的数量
SELECT COUNT(ENAME) FROM emp;
– 最高工资的员工信息
SELECT *,MAX(SAL) FROM emp;
– 1.得到最高工资 5000
select MAX(sal) from emp;
– 2. 看谁的工资等于最高工资
select * from emp where sal = (select MAX(sal) from emp);
– 3.返回员工和其所属领导的姓名。(自连接)
SELECT e.ename,d.ename FROM emp e,emp d WHERE e.mgr=d.empno;
– 最少工资的员工信息
SELECT *,MIN(SAL) FROM emp;
– 查询员工编号,员工姓名,经理编号,经理姓名
select e.empno,e.ename,e.mgr,m.ename from emp e,emp m where e.mgr = m.empno;
– 查询出高于10号部门的平均工资的员工信息
– 1.查询10号的平均工资 2916
select avg(sal) from emp where deptno=10;
– 2. 看哪些员工的工资 > 10号部门的平均工资
select * from emp where sal > 2916;
– 3.返回员工和其所属领导的姓名。(自连接)
SELECT e.ename,d.ename FROM emp e,emp d WHERE e.mgr=d.empno;
– 4.返回雇员的雇佣日期 早于其领导雇佣日期的 员工及其领导姓名。(在日期类型可以直接比较)
SELECT e.ename,d.ename FROM emp e,emp d WHERE e.MGR=d.EMPNO AND e.HIREDATE<d.HIREDATE;
– 5.返回员工姓名及其所在的部门名称。
SELECT e.ename,d.dname FROM emp e,dept d WHERE e.DEPTNO=d.DEPTNO;
– 6.返回从事clerk工作的 员工姓名和 所在部门名称
SELECT e.ename,d.dname FROM emp e,dept d WHERE e.DEPTNO=d.DEPTNO AND e.JOB="clerk";
– 7.返回部门号及其本部门的最低工资。
SELECT deptno,MIN(sal) FROM emp GROUP BY deptno;
– 8.返回销售部(sales)所有员工的姓名。
SELECT ename FROM emp WHERE job="salesman";
– 9.返回工资多于平均工资的员工。
SELECT ename FROM emp WHERE sal>(SELECT AVG(sal) FROM emp)
– 10.返回与SCOTT从事相同工作的员工。
SELECT ename FROM emp WHERE job = (SELECT job FROM emp WHERE ename="smith")
– 11.返回与30部门员工工资相同的员工姓名与工资。
SELECT sal FROM emp WHERE deptno=30
SELECT ename sal FROM emp WHERE sal IN(SELECT sal FROM emp WHERE deptno=30)
– 查询出比10号部门任何员工薪资高的员工信息 (多行子查询)
select * from emp where deptno = 10;
– 查询10号最低工资
select MIN(sal) from emp where deptno =10;
– 结果
select * from emp where sal > (select MIN(sal) from emp where deptno =10);
– 1. 查询10号部门所有的工资
select sal from emp where deptno =10;
– 2. 查询出比10号部门任何员工薪资高的员工信息
select * from emp where sal >any(select sal from emp where deptno =10);
– from 后面子查询
– 查询emp表中经理信息
– 1.查询经理的编号
select distinct mgr from emp;
– 2.将上面的查询结果当作是一张表
from
emp e,
(select distinct mgr from emp) t
where
e.empno = t.mgr;```
-- 查询 薪资 大于 薪资最高的员工 所在部门 的平均工资 和 薪资最低的员工 所在部门 的平均工资 的平均工资 的员工信息
-- sal > 10 100 and 20 80 (100+80)/2
-- sal > (100+80)/2
-- 1. 薪资最高的员工 所在部门 10
```select MAX(sal) from emp; --5000```
```select deptno from emp where sal=(select MAX(sal) from emp);```
-- 2.10号部门的平均工资 2916
```select avg(sal) from emp where deptno=(select deptno from emp where sal=(select MAX(sal) from emp));```
-- 3. 薪资最低的员工 所在部门 20
```select MIN(sal) from emp; --800```
```select deptno from emp where sal=(select MIN(sal) from emp);```
-- 4.20号部门的平均工资 2175
```select avg(sal) from emp where deptno=(select deptno from emp where sal=(select MIN(sal) from emp));```
-- 5. 10号部门 和 20号部门的平均工资
```select (10+20)/2;```
-- 6. 结果
select * from emp where sal > (2916+2175)/2;
<div class="se-preview-section-delimiter"></div>
```select * from emp where sal > (
(select avg(sal) from emp where deptno=(select deptno from emp where sal=(select MAX(sal) from emp)))
+
(select avg(sal) from emp where deptno=(select deptno from emp where sal=(select MIN(sal) from emp)))
)/2;
– 笔试题
create table test(
name char(20),
kecheng char(20),
fenshu char(20)
);
insert into test values(‘张三’,’语文’,81),
(‘张三’,’数学’,75),
(‘李四’,’语文’,76),
(‘李四’,’数学’,90),
(‘王五’,’语文’,81),
(‘王五’,’数学’,82);
– 请用一条Sql语句查处每门分数都大于80的学生
– 1.先查哪些人分数小于等于80
select name from test where fenshu <=80;
– 2.结果:
select * from test where name not in(select name from test where fenshu <=80);
select * from emp;
/*
什么多表查询: 一次查询多张表
多表之间的关系如何维护: 外键约束,foreign key , 约束一张表中的数据必须是参考另外一张表中的数据
alter table product add foreign key(cno) references category(cid)
表关系的分类:
一对多|多对一: 在多的一方添加一列,指向一的一方,添加外键约束
多对多: 插入一张中间表,中间表至少要有两列,分别指向原来两张表的主键, 将多对多的关系拆成了两个一对多关系
一对一:
1.将两张表建在同一张表中
2.将一对一的关系当作是一对多的关系,在多的一方添加的列要给它指定外键约束和唯一约束
3.将两张表的主键填写一致
多表之间的查询:
1.内连接查询:
select * from A , B where A.字段 = B.字段 (隐式内连接)
select * from A inner join B on A.字段 = B.字段 (显式内连接)
2.左外连接:
select * from A left outer join B on A.字段 = B.字段
3.右外连接:
select * from A right outer join B on A.字段 = B.字段
子查询: 查询语句中嵌套查询语句
*/