自学MySQL第二天

  MySQL进阶

一、 约束

什么是约束?

为了确保表中数据的完整性, 为表添加了一些限制, 是数据库汇总表设计最基本的一种规则; 减少了冗余数据(脏数据)

约束有五种约束:

  1. 主键约束
  2. 唯一约束
  3. 非空约束
  4. 默认约束
  5. 外键约束

(一)主键约束

PRIMARY KEY 约束,简称PK用于标识数据库表中的每条记录是唯一不重复的并且不为空主键一般设置在id;

添加主键约束

l 方式一:创建表时,在字段描述处,声明指定字段为主键:

CREATE  TABLE  p1(

id int PRIMARY KEY,

name varchar(200),

idCard varchar(50)

)

 

 

 

错误信息: 多个主键被定义

方式二:创建表时,在constraint约束区域,声明指定字段为主键:

创建格式:[constraint 名称] primary key (字段列表)

关键字constraint可以省略,如果需要为主键命名,constraint不能省略,主键名称一般没用。

CREATE TABLE p2(

id int,

name varchar(200),

idCard varchar(50),

PRIMARY KEY(id)

)

 

 

 

 

 

 

 

 

以上称之为联合主键: 多个字段需要同时使用, 结合一起组成了一个主键(单个值重复是可以正常添加的, 但是多个字段的值不可以同时重复)

l 方式三:创建表之后,通过修改表结构,声明指定字段为主键:

CREATE TABLE p4(

id int,

name varchar(200),

idCard varchar(50)

)

写法格式:

Alter table 表名 add primary key(字段名);

 

 

 

 

#因为一般主键都是提前确定好的都是跟随表一起创建

删除主键约束:(扩展-了解)

如需删除 PRIMARY KEY 约束,请使用下面的 SQL

ALTER TABLE 表名 DROP PRIMARY KEY;

注意:

主键一旦确定, 实际开发中不会轻易去删除;

(二)唯一约束

唯一约束用来限定表中某列数据不允许重复,与主键约束类似,但级别没有主键高。一个表中唯一约束可以创建多个,并且唯一约束的列允许为空。

唯一约束一般用于约束手机号、账号、邮箱等信息。

唯一约束关键字: unique

添加唯一约束

方式1:创建表时,在字段描述处,声明唯一:

CREATE TABLE p5(

id int,

name varchar(200),

idCard varchar(50)

)

 

 

 

 

 

 

 

 

方式2:创建表时,在约束区域,声明唯一:

CREATE TABLE p7(

id int,

name varchar(200),

idCard varchar(50)

)

 

 

 

 

删除唯一约束(扩展-了解)

如需撤销 UNIQUE 约束,请使用下面的 SQL

ALTER TABLE  p6  DROP INDEX 名称;

唯一约束与主键约束的区别:

  1. 一个表中可以由多个唯一约束, 但是一个表中只能有一个主键约束;
  2. 唯一约束唯一不重复但是可以为空值, 主键约束唯一不重复, 并且非空;

注意:

唯一约束一旦确定, 实际开发不会轻易删除;

(三)非空约束

NOT NULL 约束强制列不接受 NULL 值。

NOT NULL 约束强制字段始终包含值。这意味着,如果不向字段添加值,就无法插入新记录或者更新记录。

CREATE TABLE p8(

id int,

name varchar(200),

idCard varchar(50)

)

 

 

 

 

(四)默认约束

可能通过default设置默认值约束,设置了默认约束的列,如果不给值就会使用默认值来填充。

 

 

 

 

 

注意:

  1. 当性别列不给值时使用默认值填充;
  2. 当性别列指定default关键字时, 也会使用默认值;
  3. 当给性别一个新值时, 会替代默认值;

(五)外键约束

外键约束用来在两个表的数据之间建立关联,MySQL数据库是关系型数据库,即表与表之间是存在关系的,而这种关系我们就称之为外键关系。

 

 

 

 

外键的作用:

将多表之间建立联系

何为主表何为从表?

主表: 数据提供方(一方)

从表: 数据使用方(多方)

代码准备:

#创建分类表:

CREATE TABLE category(

cid varchar(32) PRIMARY KEY,#主键ID

cname VARCHAR(20)#分类名称

);

INSERT INTO category VALUES('c001','电脑办公');

INSERT INTO category VALUES('c002','服装');

#创建商品表:

CREATE TABLE product(

pid INT PRIMARY KEY,#主键ID

pname VARCHAR(20),#商品名称

price DOUBLE,#商品价格

category_cid VARCHAR(32)#外键

);

INSERT INTO product(pid,pname,price,category_cid) VALUES(1,'联想电脑',5000,'c001');

INSERT INTO product(pid,pname,price,category_cid) VALUES(2,'海尔电脑',3000,'c001');

INSERT INTO product(pid,pname,price,category_cid) VALUES(3,'雷神电脑',5000,'c001');

INSERT INTO product(pid,pname,price,category_cid) VALUES(4,'JACK JONES',800,'c002');

INSERT INTO product(pid,pname,price,category_cid) VALUES(5,'真维斯',200,'c002');

INSERT INTO product(pid,pname,price,category_cid) VALUES(6,'花花公子',440,'c002');

INSERT INTO product(pid,pname,price,category_cid) VALUES(7,'劲霸',2000,'c002');

 

 

 

 

为了保证数据的完整性, 需要添加外键约束, 确保数据达到完整性;

声明外键约束:

格式:

alter table 从表 add  foreign key (从表外键字段名) references 主表 (主表的主键);

 

 

 

 

添加数据:

先添加主表中的数据, 在添加从表中的数据;

删除数据:

先删除从表中的数据, 确保主表中的数据没有被引用, 再删除主表中的数据;

如果为从表添加外键约束,必须保证:

从表外键的数据类型和长度,必须和主表主键数据类型和长度 一致

从表和主表为空,或者数据必须完整

(六)自动增长-策略

我们通常希望在每次插入新记录时,数据库自动生成字段的值。

我们可以在表中使用 auto_increment(自动增长列)关键字,自动增长列类型必须是整形,自动增长列必须为主键

CREATE TABLE p9(

id int PRIMARY KEY,

name varchar(200),

idCard varchar(50)

)

 

 

 

 

总结:(自增长特点)

  1. 只有整数型列才可以设置自增列
  2. 只有主键才可以设置自增列
  3. 自增列可以不赋值
  4. 初始化为1, 增量为1
  5. 自增列一旦使用过就不会重复出现

二、 表关系

在一个关系型数据库中,利用关系可以避免表中数据的冗余,保证数据紧密性和方便查阅

表关系的分类:

一对一关系: one_to_one         人与身份号     丈夫与妻子

一对多关系: one_to_many        商品与分类    用户与订单    班级与学生

多对多关系(双向一对多): many_to_many    老师与学生  商品与订单  演员与角色  

(一)一对一关联

一对一关联:

在实际的开发中应用不多.因为一对一可以合成一张表。

建表方式:

外键唯一:主表的主键和从表的外键(唯一),形成主外键关系,外键唯一unique

(二)一对多关联

一对多关系中,一方的表称为主表,多方的表称为从表。在从表中添加一个外键用来关联主表的主键,这样就可以实现一对多关系。

应用场景:

商品与分类    用户与订单    班级与学生

建表方式:

 

 

 

 

(三)多对多关联

两张表AB想要实现多对多关系,需要借助一张中间表C,在C中设置两个外键,分别关联AB表的主键。

应用场景:

老师与学生  商品与订单  演员与角色

建表方式:

 

 

 

 

(四)实战演练

实战1:省和市

 

 

 

 

代码准备:

CREATE TABLE province(

id INT PRIMARY KEY,

NAME VARCHAR(20),

description VARCHAR(20)

);

CREATE TABLE city(

id INT PRIMARY KEY,

NAME VARCHAR(20),

description VARCHAR(20)

);

 

 

 

 

实战2:用户和角色(多对多关系)

代码准备:

create table actor(

aid int primary key,

name varchar(30)

);

create table role(

rid int primary key,

name varchar(30)

);

 

 

 

 

三、 连接查询

连接查询就是将多张表中的数据按照指定连接条件一起查询出来;

常见的连接查询:

  1. 内连接查询
  2. 外连接查询

以下准备两张表演练连接查询:

部门表:

 

 

 

 

员工表:

 

 

 

 

 

  1. 内连接查询:

内连接查询:

两张表或者多张表按照特定的关联关系关联在一起, 实现查询,返回的是查询两张表的交集;

图解:

 

 

 

 

内连接分为:

l 隐式内连接

l 显示内连接

 

隐式内连接:

两张表或者多张表按照特定的关联关系关联在一起实现查询, 对于隐式内连接查询, 表与表之间使用逗号隔开, 使用where设置两张表的关联条件;

写法格式:

Select * from 1, 2 where [关联条件];

#查询每个部门下有哪些员工?

 

 

 

 

查询结果:

 

 

 

 

#查询开发部门下有哪些员工?

 

 

 

 

查询结果:

 

 

 

 

注意事项:

  1. 1与表2之间的顺序是可以相互调换的;
  2. 如果不添加where条件, 会出现笛卡尔积现象; 查询的是两张表的乘积, 没有任何意义;如何避免笛卡尔积现象, 添加where关联条件;

 

 

 

 

  1. 如果在连接查询中起了别名, 在使用的时候一定要使用别名;

错误写法:

 

 

 

 

正确写法:(使用别名.字段名)

 

 

 

 

  1. 如果两张表中出现了同名的字段, 一定要在前边加上表名; 例如: 表名(别名).字段名

显示内连接

两张表或者多张表按照特定的关联关系关联在一起实现查询, 对于显示内连接, 使用inner join将两张表关联在一起, 使用on设置关联条件;

写法格式:

Select * from 1 inner join 2 on [关联条件];

 

 

 

 

 

 

 

查询结果:

 

 

 

 

 

 

 

查询结果:

 

 

 

 

  1. 外连接查询

外连接查询:

两张表或者多张表联合查询, 以一张表为基准(需要显示该表的全部数据), 另一张表显示与该表中对应的数据, 如果没有对应的数据, 则以null补全;

外连接查询:

左外连接查询 右外连接查询

 

左外连接查询:

关键字: left join ... on ...

写法格式:

Select * from 1 left join 2 on [关联条件];

特点:

以左表为基准, 去匹配右表中的数据, 如果匹配到了, 将显示全部显示;

如果匹配不到, 左表中的数据全部显示, 而右表中的数据以null补全;

图解:

 

 

 

右外连接查询:

关键字: right join ... on ...

写法格式:

Select * from 1 right join 2 on [关联条件];

特点:

以右表为基准, 去匹配左表中的数据, 如果匹配到了, 将显示全部显示;

如果匹配不到, 右表中的数据全部显示, 而左表中的数据以null补全;

图解:

 

 

 

# 查询所有员工信息以及部门名称(分别使用左外连接和右外连接)

 

 

 

查询结果:

 

 

 

 

 

 

查询结果:

 

 

 

总结:

内连接和外连接的区别:

  1. 内连接查询的是两张表的交集, 去掉没有连接条件的数据
  2. 外连接查询是以其中一张表为基准, 去匹配另外一张表, 如果匹配到了, 显示对应的数据, 如果匹配不到, 则以null补全;

四、 聚合函数

SQL中存在一些聚合函数对一组值进行数据统计,并返回单个值,也被称为组函数。这些特殊函数是不能直接在where后面当做条件使用的经常与 SELECT 语句的 GROUP BY 子句的HAVING一同使用。(where后不能跟聚合函数, having后可以跟聚合函数)

聚合函数包括:

l count(字段):统计数量;

l sum(字段):计算指定列的和  

l max(字段):计算指定列的最大值;

l min(字段):计算指定列的最小值;

l avg(字段):计算指定列的平均值;

代码准备:

#1 查询商品的总条数

#查看商品总价格、最大价格、最小价格、价格的平均值

#2 查询价格大于200商品的总条数

#3 查询分类为'电脑办公'的所有商品的总记录

#4 查询分类为'服装'所有商品的平均价格

 

 

 

五、 分组查询

分组查询关键字:group  by

分组查询的原理:对数据进行分组,对分组后的数据进行汇总。 分组查询通常用于配合聚合函数,达到分类汇总统计信息的目的。而其分类汇总的本质实际上就是先将信息分组分组后相同类别的信息会聚在一起,然后通过需求进行统计计算。

写法格式:

Select * from 表名 group by 分组字段;

代码准备:

#1 统计各个分类下的商品的个数

#2 统计各个分类商品的个数,且只显示分类名不为空值的数据

 

 

 

Where having的区别:(面试题)

  1. Where不能放在group by分组后;
  2. Having是跟在group by分组后, 需要连在一起使用;

注意事项:

二者可以同时去使用, where子句优先于having执行, where 必选放在分组前, having必须放在分组后使用;where后不能跟聚合函数, having后可以跟聚合函数; where属于第一次筛选过滤,

分组的二次筛选过滤使用having;

Select查询书写顺序(重点)

SELECT 字段 FROM 表名 WHERE 条件 GROUP BY(分组) 字段 HAVING 条件 ORDER BY(排序) 字段;

其中SELECT字段,FROM表名为 必写,其余均可根据情况而定

执行顺序:(了解)

1. From 表名

2. Where  条件 (第一次条件筛选)  

3. Group by 字段   字段值相同的数据会划分成一组

4. Having 条件     对每一组分别进行一次运算(二次条件筛选)

5. Select 字段      把每组中第一条数据取出来。合并成一张新伪表

6. 展示这个新伪表上的部分字段

7. order by 字段    对新伪表进行最后排序

六、 查询

子查询:

当一个查询时另一个查询的条件时, 称之为自查询, 也叫嵌套查询;

在多表操作中,子查询是常见的查询方式

子查询的三种情况:

I子查询的结果是一个值的时候

 

 

 

需求:

1、 查询工资最高的员工是

 

 

 

2、 查询工资小于平均工资的员工有哪些

 

 

 

 

II子查询结果是单多行的时候

 

 

 

需求:

1、查询工资大于5000的员工,来自于哪些部门的名字

 

 

 

2、查询开发部与财务部所有员工的信息

 

 

 

 

III、子查询的结果是多行多列

 

 

 

需求:查询出2011年以后入职的员工信息,包括部门名称

 

 

 

通过以上子查询得出结论:

子查询结果只要是 单列 ,肯定在 WHERE 后面作为 条件

SELECT 查询字段 FROM WHERE 字段 =(子查询)

子查询结果只要是 多列 ,肯定在 FROM 后面作为 表

SELECT 查询字段 FROM (子查询) 表别名 WHERE 条件

七、 数据的备份和恢复

可视化工具:

备份:

 

 

 

 

 

 

 

证明备份成功;

恢复:

 

 

 

 

 

 

八、 SQL多表查询综合练习

代码准备:

#部门表

CREATE TABLE dept (

  id INT PRIMARY KEY,

  dname VARCHAR(50),

  loc VARCHAR(50)

);

 

#添加4个部门

INSERT INTO dept(id,dname,loc) VALUES (10,'教研部','北京'),(20,'学工部','上海'),(30,'销售部','广州'),(40,'财务部','深圳');

 

#职务表,职务名称,职务描述

CREATE TABLE job (

  id INT PRIMARY KEY,

  jname VARCHAR(20),

  description VARCHAR(50)

);

 

#添加4个职务

INSERT INTO job (id, jname, description) VALUES(1, '董事长', '管理整个公司,接单'),(2, '经理', '管理部门员工'),(3, '销售员', '向客人推销产品'),(4, '文员', '使用办公软件');

 

#员工表

CREATE TABLE emp (

  id INT PRIMARY KEY, -- 员工id

  ename VARCHAR(50), -- 员工姓名

  job_id INT, -- 职务id

  mgr INT , -- 上级领导

  joindate DATE, -- 入职日期

  salary DECIMAL(7,2), -- 工资

  bonus DECIMAL(7,2), -- 奖金

  dept_id INT, -- 所在部门编号

  CONSTRAINT emp_jobid_ref_job_id_fk FOREIGN KEY (job_id) REFERENCES job (id),

  CONSTRAINT emp_deptid_ref_dept_id_fk FOREIGN KEY (dept_id) REFERENCES dept (id)

);

 

#添加员工

INSERT INTO emp(id,ename,job_id,mgr,joindate,salary,bonus,dept_id) VALUES

(1001,'孙悟空',4,1004,'2000-12-17','8000.00',NULL,20),

(1002,'卢俊义',3,1006,'2001-02-20','16000.00','3000.00',30),

(1003,'林冲',3,1006,'2001-02-22','12500.00','5000.00',30),

(1004,'唐僧',2,1009,'2001-04-02','29750.00',NULL,20),

(1005,'李逵',4,1006,'2001-09-28','12500.00','14000.00',30),

(1006,'宋江',2,1009,'2001-05-01','28500.00',NULL,30),

(1007,'刘备',2,1009,'2001-09-01','24500.00',NULL,10),

(1008,'猪八戒',4,1004,'2007-04-19','30000.00',NULL,20),

(1009,'罗贯中',1,NULL,'2001-11-17','50000.00',NULL,10),

(1010,'吴用',3,1006,'2001-09-08','15000.00','0.00',30),

(1011,'沙僧',4,1004,'2007-05-23','11000.00',NULL,20),

(1012,'李逵',4,1006,'2001-12-03','9500.00',NULL,30),

(1013,'小白龙',4,1004,'2001-12-03','30000.00',NULL,20),

(1014,'关羽',4,1007,'2002-01-23','13000.00',NULL,10);

 

#工资等级表

CREATE TABLE salarygrade (

  grade INT PRIMARY KEY,   -- 级别

  losalary INT,  -- 最低工资

  hisalary INT -- 最高工资

);

 

#添加5个工资等级

INSERT INTO salarygrade(grade,losalary,hisalary) VALUES

(1,7000,12000),

(2,12010,14000),

(3,14010,20000),

(4,20010,30000),

(5,30010,99990);

代码准备:

#练习1查询所有员工信息。显示员工编号,员工姓名,工资,职务名称,职务描述

 

#练习2查询所有员工信息。显示员工编号,员工姓名,工资,职务名称,职务描述,部门名称,部门位置

 

#练习3查询所有员工信息。显示员工姓名,工资,职务名称,职务描述,部门名称,部门位置,工资等级

 

#练习4查询经理的信息。显示员工姓名,工资,职务名称,职务描述,部门名称,部门位置,工资等级

 

#练习5查询出部门编号、部门名称、部门位置、部门人数

 

#练习6查询所有员工信息。显示员工信息和部门名称,没有员工的部门也要显示

 

#练习7查询所有员工信息。显示员工姓名,员工工资,职务名称,工资等级,并按工资升序排序

 

#练习8列出所有员工的姓名及其直接上级的姓名,没有领导的员工也需要显示

 

#练习9查询入职期早于直接上级的所有员工编号、姓名、部门名称

 

#练习10查询工资高于公司平均工资的所有员工信息。显示员工信息,部门名称,上级领导,工资等级

#练习1查询所有员工信息。显示员工编号,员工姓名,工资,职务名称,职务描述

SELECT e.id '员工编号', e.ename '员工姓名', e.salary '工资', j.jname '职务名称', j.description '职务描述'

FROM emp e, job j

WHERE e.job_id = j.id;

 

#练习2查询所有员工信息。显示员工编号,员工姓名,工资,职务名称,职务描述,部门名称,部门位置

SELECT e.id '员工编号', e.ename '员工姓名', e.salary '工资', j.jname '职务名称',

j.description '职务描述', d.dname '部门名称', d.loc '部门位置'

FROM emp e, job j, dept d

WHERE e.job_id = j.id

AND e.dept_id = d.id;

 

#练习3查询所有员工信息。显示员工姓名,工资,职务名称,职务描述,部门名称,部门位置,工资等级

SELECT e.ename '员工姓名', e.salary '工资', j.jname '职务名称',

j.description '职务描述', d.dname '部门名称', d.loc '部门位置', s.grade '工资等级'

FROM emp e, job j, dept d, salarygrade s

WHERE e.job_id = j.id

AND e.dept_id = d.id

AND e.salary

BETWEEN s.losalary AND s.hisalary;

 

#练习4查询经理的信息。显示员工姓名,工资,职务名称,职务描述,部门名称,部门位置,工资等级

SELECT e.ename '员工姓名', e.salary '工资', j.jname '职务名称',

j.description '职务描述', d.dname '部门名称', d.loc '部门位置', s.grade '工资等级'

FROM emp e, job j, dept d, salarygrade s

WHERE e.job_id = j.id

AND e.dept_id = d.id

AND e.salary

BETWEEN s.losalary AND s.hisalary

AND j.jname='经理';

 

#练习5查询出部门编号、部门名称、部门位置、部门人数

SELECT d.id '部门编号', d.dname '部门名称', d.loc '部门位置', COUNT(*) '部门人数'

FROM dept d, emp e

WHERE d.id = e.dept_id

GROUP BY d.id;

 

#练习6查询所有员工信息。显示员工信息和部门名称,没有员工的部门也要显示

SELECT e.*, d.dname

FROM dept d

LEFT JOIN emp e

ON e.dept_id = d.id;

 

#练习7查询所有员工信息。显示员工姓名,员工工资,职务名称,工资等级,并按工资升序排序

SELECT e.ename '员工姓名', e.salary '员工工资', j.jname '职务名称', s.grade '工资等级'

FROM emp e, job j, salarygrade s

WHERE e.job_id = j.id

AND e.salary

BETWEEN s.losalary AND s.hisalary

ORDER BY e.salary ASC;

 

#练习8列出所有员工的姓名及其直接上级的姓名,没有领导的员工也需要显示(自查询)

SELECT e.ename '员工姓名', m.ename '直接上级领导'

FROM emp e

LEFT JOIN emp m

ON e.mgr = m.id;

 

#练习9查询入职期早于直接上级的所有员工编号、姓名、部门名称

SELECT e.id '员工编号', e.ename '姓名', d.dname '部门名称'

FROM emp e, emp m, dept d

WHERE e.mgr = m.id

AND e.dept_id = d.id

AND e.joindate < m.joindate;

 

#练习10查询工资高于公司平均工资的所有员工信息。显示员工信息,部门名称,上级领导,工资等级

#平均工资

SELECT AVG(salary) FROM emp;

 

SELECT e.*, d.dname '部门名称', m.ename '上级领导', s.grade '工资等级'

FROM emp e

LEFT JOIN emp m ON e.mgr = m.id -- 直接上级领导

INNER JOIN dept d ON e.dept_id = d.id -- 部门信息

INNER JOIN salarygrade s ON e.salary

BETWEEN s.losalary AND s.hisalary -- 工资等级

AND e.salary > (SELECT AVG(salary) FROM emp);

posted @ 2020-09-15 19:16  master_hxh  阅读(179)  评论(0编辑  收藏  举报