重学JavaWeb(9)MySQL约束与多表查询

1. 约束

1. 约束的作用:为了保证数据的有效性和完整性
2. MySQL中常用的约束

1. 主键约束:primary key
2. 自增长约束:auto_incrment
3. 唯一约束:unique
4. 非空约束:not null
5. 外键约束:foreign key
6. 枚举约束:enum
7. 非负约束:unsigned

3. 主键约束
(1)主键约束的数据非空且唯一,一张表中只有一个主键
(2)添加主键的方式

-- 添加主键方式1:在建表的时候直接添加
create table test(
	username varchar(20) primary key,
	password varchar(20)
)
insert into test values('aaa','123456');
insert into test values('bbb','12345');

-- 添加主键方式2:表中添加
CREATE TABLE test2(
	username VARCHAR(20),
	PASSWORD VARCHAR(20),
	primary key(username)
);
INSERT INTO test2 VALUES('aaa','123456');
INSERT INTO test2 VALUES('bbb','12345');

-- 添加方式3:表外添加
create table test3(
	username varchar(20),
	password varchar(20)
);
alter table test3 add primary key(username);
insert into test3 values('aaa','123456');
insert into test3 values('bbb','12345');

-- 联合主键:把多个字段看成一个整体,设定为主键
-- 添加联合主键方式:表外添加
CREATE TABLE test4(
	username VARCHAR(20),
	PASSWORD VARCHAR(20)
);
alter table test4 add primary key(username,password);

4. 自增长约束
(1)如果某一列是数值类型的,使用auto_increment来完成自增长
(2)添加自增长的方式

-- 添加主键自增长
CREATE TABLE test5(
	id int primary key auto_increment,
	username VARCHAR(20),
	PASSWORD VARCHAR(20)
);

(3)注意:当你删除了一条数据时,下次再添加一条,不会再用之前删除的那条主键的值

5. 唯一约束
(1)unique,某一列的值不能重复
(2)注意:唯一约束可以有mull值,但是只能有一条记录为null
(3)添加方式

-- 添加唯一约束
CREATE TABLE test6(
	id INT PRIMARY KEY AUTO_INCREMENT,
	username VARCHAR(20) UNIQUE,
	PASSWORD VARCHAR(20)
);

6. 非空约束
(1)not null,某一列的值不能为null
(2)添加方式

-- 添加非空约束
CREATE TABLE test6(
	id int primary key auto_increment,
	username VARCHAR(20) unique not null,  -- 唯一且非空
	PASSWORD VARCHAR(20) not null  -- 非空
);

7. 非负约束
(1)unsigned,某一列的值不能为负
(2)添加方式

-- 添加非负约束
CREATE TABLE test7(
	id INT PRIMARY KEY AUTO_INCREMENT,
	age TINYINT UNSIGNED  -- 非负约束
);

(3)注意:原本TINYINT这个数据类型可以表示的范围是-128–127,添加了非负约束后,TINYINT的范围就变成了0–255

8. 枚举约束
(1)enum,该列只能远枚举中出现的
(2)添加方式

-- 添加枚举约束
CREATE TABLE test8(
	id INT PRIMARY KEY AUTO_INCREMENT,
	username VARCHAR(20),
	sex ENUM('男','女','妖')  -- 枚举约束
);

2. 数据库的设计

1. 实体与实体之间的关系
(1)一对多:用户表(1) – 订单表(N),我们把1这一方的表称为主表或者单表,把N这一方的表称为多表或者从表
(2)多对多:订单表(N) – 商品表(N)
(3)一对一

2. 一对多关系
(1)为了保证数据的有效性和完整性,可以去添加外键约束,让两张表之间形成外键约束,来避免数据的不合理
(2)一般会在多表的一方添加外键约束,去关联主表一方的主键
(3)如果添加了外键约束,则有如下特点

1. 主表一方,不能删除从表还在引用的数据
2. 从表一方,不能添加主表没有描述的数据

(4)级联删除 / 级联更新:ON DELETE CASCADE / ON UPDATE CASCADE
(5)代码示例

-- 外键与级联操作的添加方式
-- 用户表
create table users(
	id int primary key auto_increment,
	username varchar(20)
);
-- 订单表
create table orders(
	id int primary key auto_increment,
	totalprice double,
	users_id int,
	foreign key(users_id) references users(id) on delete cascade on update cascade
);

3. 多对多关系
(1)多对多关系需要借助第三张中间表。中间表至少包含两个字段,这两个字段作为第三张表的外键,分别关联两张表的主键
(2)代码示例

-- 订单表
CREATE TABLE orders(
	id INT PRIMARY KEY AUTO_INCREMENT,
	totalprice DOUBLE,
	users_id INT,
	FOREIGN KEY(users_id) REFERENCES users(id) ON DELETE CASCADE ON UPDATE CASCADE
);

-- 商品表
CREATE TABLE product(
	id  INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(20),
	price DOUBLE
);

-- 中间表
CREATE TABLE orderitem(
	oid INT,
	pid INT,
	FOREIGN KEY(oid) REFERENCES orders(id),
	FOREIGN KEY(pid) REFERENCES product(id)
)

3. 多表查询

1. 概念:在进行多表查询时,要有关联条件,如果是N张表关联查询,至少需要N-1个关联条件
2. 查询语法

select
	列名列表
from
	表名列表
where
	...

3. 具体细节
(1)内连接查询(隐式内连接):使用where条件消除无用数据

-- 查询所有员工信息和对应的部门信息
select * from emp,dept where emp.'dept_id' = dept.'id'
-- 查询员工表的名称,性别。部门表的名称
select emp.name,emp.gender,dept.name from emp,dept where emp.'id' = dept.'id'

select
	t1.name,   -- 员工表的姓名
	t1.gender,  -- 员工表的性别
	t2.name   -- 部门表的名称
from
	emp t1,
	dept t2
where 
	t1.'dept_id' = t2.'id';

(2)外连接

1. 左外连接(常用):
	(1)语法:select 字段列表 from1 left [outer] join2 on 条件;2)查询的是左表所有数据以及其交集部分
	(3)例子
		-- 查询所有员工信息,如果员工有部门,则查询部门名称,没有部门则不显示部门
		select t1.*,t2.'name' from emp t1 left join dept t2 on t1.'dept_id' = t2.'id';
2. 右外连接:
	(1)语法:select 字段列表 from1 right [outer] join2 on 条件;2)查询的是右表所有数据已集齐交集部分
	(3)例子
		select * from dept t2 right join emp t1 on t1.'dept_id' = t2.'id'

(3)子查询

1. 概念:查询中嵌套查询,称嵌套查询为子查询
2. 例子
	-- 查询工资最高的员工信息
	-- 1.查询最高工资是多少 9000
	select max(salary) from emp;
	-- 2.查询员工信息,使工资等于9000
	select * from emp where emp.'salary' = 9000;

	-- 一条sql语句即可完成
	select * from emp where emp.'salary' = (select max(salary) from emp);
3. 子查询的不同情况
	(1)子查询的结果可以是单行单列的
		子查询可以作为条件,使用运算符去判断。(运算符:> < = >= <=-- 查询员工工资小于平均工资的人
		select * from emp where emp.salary < (select avg(salary) from emp);2)子查询的结果可以是多行单列的
		子查询可以作为条件,使用运算符in来判断
		-- 查询‘财务部’和‘市场部’所有员工的信息
		select id from dept where name = '财务部' or name = '市场部';
		select * from emp where dept_id = 3 or dept_id = 2;
		-- 子查询
		select * from emp where dept_id in (select id from dept where name = '财务部' or name = '市场部');3)子查询的结果可以是多行多列的
		子查询可以作为一张虚拟表参与查询
		-- 查询员工入职日期是2011-11-11之后的员工信息和部门信息
		-- 子查询
		select 
			* 
		from 
			dept t1,(select * from emp where emp.'join_date' > '2011-11-11') t2
		where
			t1.id = t2.dept_id;

(4)多表查询练习

1. 找到需要使用的表
2. 在需要的表中找到表之间的联系
-- 部门表
CREATE TABLE dept (
	id INT PRIMARY KEY PRIMARY KEY, -- 部门id
	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. 查询所有员工信息。查询员工编号,员工姓名,工资,职务名称,职务描述
/*
分析:
	1. 员工编号,员工姓名,工资需要查询emp表,职务名称,职务描述需要查询job表
	2. 查询条件 emp.job_id = job.id
*/
select 
	t1.'id',   -- 员工编号
	t1.'ename',  -- 员工姓名
	t1.'salary',   -- 员工工资
	t2.'jname',   -- 职务名称
	t2.'description'   -- 职务描述
from
	emp t1,job t2
where
	t1.'job_id' = t2.'id';

-- 2. 查询员工编号,员工姓名,工资,职务名称,职务描述,部门名称,部门位置
/*
分析:
	1. 员工编号、员工姓名、工资emp表,职务名称、职务描述job表,部门名称、部门位置dept表
	2. 条件:emp.job_id = job.id and emp.dept_id = dept.id
*/
select 
	t1.'id',   -- 员工编号
	t1,'ename',   -- 员工姓名
	t1.'salary',   -- 员工工资
	t2.'jname',   -- 职务名称
	t2.'description',   -- 职务描述
	t3.'dname',   -- 部门名称
	t3.'loc'   -- 部门位置
from
	emp t1,job t2,dept t3
where
	t1.'job_id' = t2.'id' and t1.'dept_id' = t3.'id';

-- 3. 查询员工姓名,工资,工资等级
/*
分析:
	1. 员工姓名、工资emp表,工资等级salarygrade表
	2. 条件 emp.salary >= salarygrde.losalary and emp.salary <= salarygrde.hisalary
			emp.salary between salarygrade.losalary and salarygrade.hisalary
*/
select
	t1.ename,
	t1.'salary',
	t2.*
from
	emp t1,salarygrade t2
where
	t1.'salary' between t2.'losalary' and t2.'hisalary';

-- 4.查询员工姓名,工资,职务名称,职务描述,部门名称,部门位置,工资等级
/*
分析:
1. 员工姓名,工资 emp,职务名称,职务描述 job 部门名称,部门位置,dept  工资等级 salarygrade
2. 条件: emp.job_id = job.id and emp.dept_id = dept.id and emp.salary BETWEEN salarygrade.losalary and salarygrade.hisalary
*/
SELECT 
	t1.`ename`,
	t1.`salary`,
	t2.`jname`,
	t2.`description`,
	t3.`dname`,
	t3.`loc`,
	t4.`grade`
FROM 
	emp t1,job t2,dept t3,salarygrade t4
WHERE 
	t1.`job_id` = t2.`id` 
	AND t1.`dept_id` = t3.`id`
	AND t1.`salary` BETWEEN t4.`losalary` AND t4.`hisalary`;	

-- 5. 查询部门编号,部门名称,部门位置,部门人数
/*
分析:
	1. 部门编号、部门名称、部门位置 dept 表。 部门人数 emp表
	2. 使用分组查询。按照emp.dept_id完成分组,查询count(id)
	3. 使用子查询将第2步的查询结果和dept表进行关联查询
*/	
select
from
	dept t1,
	(select
		dept_id,count(id) total
	 from
	 	emp
	 group by 
	 	dept_id
	) t2
where
	t1.'id' = t2.dept_id;				

4. MySQL中表的复制

-- 1. 把一张旧表中的数据,复制到一张新表中
create table 新表名 as select * from 旧表名;

-- 2. 只要想旧表的表头,不想要旧表的数据(不要表中的数据,需要写个条件为假的就行)
create table 新表名 as select * from 旧表名 where 1 = 2; 

-- 3. 复制一张表,想要个别字段
create table 新表名 as select 旧表名.字段名 from 旧表名 where 1 = 1;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值