约束
约束是作用于表中列上的规则,用于限制加入表的数据
约束的存在保证了数据库中数据的正确性,有效性和完整性
单表约束 | 描述 | 关键字 |
非空约束 | 保证列中所有数据不能有null值 | not null |
唯一约束 | 保证列中所有数据各不相同 | unique |
主键约束 | 主键是一行数据的唯一标识,要求非空且唯一,一张表只能有一个主键。 | primary key |
检查约束 | 保证列中数据的值满足某一条件 | check(MySql不支持检查约束) |
默认约束 | 保存数据时,未指定值则采用默认值 | default |
create database if not exists db2;
use db2;
DROP TABLE IF EXISTS emp;
-- 员工表
CREATE TABLE if not exists emp (
id INT primary key auto_increment, -- 员工id,主键且自增长
ename VARCHAR(50) not null unique , -- 员工姓名,非空并且唯一
joindate DATE not null , -- 入职日期,非空
salary DOUBLE(7,2) not null , -- 工资,非空
bonus DOUBLE(7,2) default 0-- 奖金,如果没有奖金默认为0
);
SELECT * from emp;
CREATE TABLE if not exists emp (
id INT auto_increment, -- 员工id,主键且自增长
ename VARCHAR(50) not null unique , -- 员工姓名,非空并且唯一
joindate DATE not null , -- 入职日期,非空
salary DOUBLE(7,2) not null , -- 工资,非空
bonus DOUBLE(7,2) default 0,-- 奖金,如果没有奖金默认为0
primary key (id) -- 设置主键
);
SELECT * from emp;
INSERT INTO emp(id,ename,joindate,salary,bonus) values(1,'张三','1999-11-11',8800,5000);
SELECT * from emp;
-- 演示主键约束:非空且唯一(Duplicate entry '1' for key 'PRIMARY')
INSERT INTO emp(id,ename,joindate,salary,bonus) values(1,'张三','1999-11-11',8800,5000);
SELECT * from emp;
-- 演示非空约束(Column 'ename' cannot be null)
INSERT INTO emp(id,ename,joindate,salary,bonus) values(2,null,'1999-11-11',8800,5000);
SELECT * from emp;
-- 演示唯一约束(Duplicate entry '张三' for key 'ename')
INSERT INTO emp(id,ename,joindate,salary,bonus) values(2,'张三','1999-11-11',8800,5000);
SELECT * from emp;
-- 演示默认约束(默认值为0)
INSERT INTO emp(id,ename,joindate,salary) values(4,'赵六','1999-11-11',8800);
SELECT * from emp;
-- 演示自动增长:auto_increment:当列是数字类型并且 唯一约束()
/*自动增长规则:计数器原理,count每次+1作为id,但是在添加数据时,还会看最后一条数据的id值,将最后一条数据的id+1
和计数器比较,谁的值大就用谁。
*/
INSERT INTO emp(ename,joindate,salary,bonus) values('王七','1999-11-11',8800,0);
SELECT * from emp;
多表约束 | 描述 | 关键字 |
外键约束 | 外键用来让两个表的数据之间建立连接,保证数据的一致性和完整性 | foreign key |
use db2;
/*
外键约束:
* 外键用来让两个表的数据之间建立链接,保证数据的一致性和完整性
-- 创建表时添加外键约束
CREATE TABLE 表名(
列名 数据类型,
…
[CONSTRAINT] [外键名称] FOREIGN KEY(外键列名) REFERENCES 主表(主表列名)
);
-- 建完表后添加外键约束
ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY (外键字段名称) REFERENCES 主表名称(主表列名称);
-- 删除约束
ALTER TABLE 表名 DROP FOREIGN KEY 外键名称;
*/
-- 删除表
DROP TABLE IF EXISTS emp;
DROP TABLE IF EXISTS dept;
-- 部门表
CREATE TABLE dept(
id int primary key auto_increment,
dep_name varchar(20),
addr varchar(20)
);
-- 员工表
CREATE TABLE emp(
id int primary key auto_increment,
name varchar(20),
age int,
dep_id int,
constraint fk_emp_dept_1 foreign key (dep_id) references dept(id)
);
-- 添加 2 个部门
insert into dept(dep_name,addr) values
('研发部','广州'),('销售部', '深圳');
-- 添加员工,dep_id 表示员工所在的部门
INSERT INTO emp (NAME, age, dep_id) VALUES
('张三', 20, 1),
('李四', 20, 1),
('王五', 20, 1),
('赵六', 20, 2),
('孙七', 22, 2),
('周八', 18, 2);
-- ------------------
select * from emp;
-- 演示外键约束(Cannot delete or update a parent row:
-- a foreign key constraint fails (`db2`.`emp`, CONSTRAINT `fk_emp_dept_1` FOREIGN KEY (`dep_id`) REFERENCES `dept` (`id`)))
delete from dept where id=2;
-- 删除外键
alter table emp drop foreign key fk_emp_dept_1;
-- 建完表后,添加外键
alter table emp add constraint fk_emp_dept_1 foreign key (dep_id) references dept(id);
数据库设计
数据库设计的步骤:
需求分析(数据是什么? 数据具有哪些属性? 数据与属性的特点是什么)
逻辑分析(通过ER图对数据库进行逻辑建模,不需要考虑我们所选用的数据库管理系统)
物理设计(根据数据库自身的特点把逻辑设计转换为物理设计)
维护设计(1.对新的需求进行建表;2.表优化)
多表设计
一对多(多对一):外键设计在多的一方,指向一的一方的主键
多对多:建立第三张中间表,中间表至少包含两个外键,分别关联两方的主键。
/*
多对多:
* 如:订单 和 商品
* 一个商品对应多个订单,一个订单包含多个商品
实现方式:建立第三张中间表,中间表至少包含两个外键,分别关联两方主键
*/
-- 删除表
DROP TABLE IF EXISTS tb_order_goods;
DROP TABLE IF EXISTS tb_order;
DROP TABLE IF EXISTS tb_goods;
use db2;
-- 订单表
CREATE TABLE tb_order(
id int primary key auto_increment,
payment double(10,2),
payment_type TINYINT,
status TINYINT
);
-- 商品表
CREATE TABLE tb_goods(
id int primary key auto_increment,
title varchar(100),
price double(10,2)
);
-- 订单商品中间表
CREATE TABLE tb_order_goods(
id int primary key auto_increment,
order_id int,
goods_id int,
count int
);
-- 建完表后,添加外键
alter table tb_order_goods add constraint fk_tb_goods_1 foreign key (goods_id) references tb_goods(id);
alter table tb_order_goods add constraint fk_tb_order_2 foreign key (order_id) references tb_order(id);
一对一:在任意一方加入外键,关联另一方主键,并设置外键为唯一(unique)
/*
一对一:
如:用户 和 用户详情
一对一关系多用于表拆分,将一个实体中经常使用的字段放一张表,不经常使用的字段放另一张表,用于提升查询性能
实现方式:在任意一方加入外键,关联另一方主键,并且设置外键为唯一(UNIQUE)
*/
use db2;
-- 删除表
DROP TABLE IF EXISTS tb_user;
DROP TABLE IF EXISTS tb_user_desc;
-- 用户详情表
CREATE TABLE tb_user_desc(
id int primary key auto_increment,
city varchar(100),
edu varchar(10),
income double(10,2),
status varchar(10),
descInfo varchar(200)
);
-- 用户表
CREATE TABLE tb_user(
id int primary key auto_increment,
phone varchar(100),
nickname varchar(20),
age int,
gender char(1),
desc_id int
);
-- 建完表后,添加外键
alter table tb_user change desc_id desc_id int unique;
alter table tb_user add constraint fk_1 foreign key (desc_id) references tb_user_desc (id);
多表查询
多表查询:从多张表查询数据,并消除笛卡尔积(笛卡尔积:取A,B集合所有组合情况)
连接查询:
内连接:相当于查询AB交集数据
外连接:
左外连接:相当于查询A表所有数据和交集部分数据
右外连接:相当于查询B表所有数据和交集部分数据
子查询 :查询语句中的嵌套查询
use db2;
DROP TABLE IF EXISTS emp;
DROP TABLE IF EXISTS dept;
-- 创建部门表
CREATE TABLE dept(
did INT PRIMARY KEY AUTO_INCREMENT,
dname VARCHAR(20)
);
-- 创建员工表
CREATE TABLE emp (
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(10),
gender CHAR(1), -- 性别
salary DOUBLE, -- 工资
join_date DATE, -- 入职日期
dep_id INT,
FOREIGN KEY (dep_id) REFERENCES dept(did) -- 外键,关联部门表(部门表的主键)
);
-- 添加部门数据
INSERT INTO dept (dNAME) VALUES ('研发部'),('市场部'),('财务部'),('销售部');
-- 添加员工数据
INSERT INTO emp(NAME,gender,salary,join_date,dep_id) VALUES
('孙悟空','男',7200,'2013-02-24',1),
('猪八戒','男',3600,'2010-12-02',2),
('唐僧','男',9000,'2008-08-08',2),
('白骨精','女',5000,'2015-10-07',3),
('蜘蛛精','女',4500,'2011-03-14',1),
('小白龙','男',2500,'2011-02-14',null);
select * from emp;
-- 多表查询
select * from emp,dept;
select * from emp e ,dept d where d.did=e.dep_id;
select * from emp left join dept d on d.did = emp.dep_id;
select * from emp right join dept d on d.did = emp.dep_id;
/*
-- 隐式内连接
SELECT 字段列表 FROM 表1,表2… WHERE 条件;
-- 显示内连接
SELECT 字段列表 FROM 表1 [INNER] JOIN 表2 ON 条件 [INNER] JOIN 表3 ON 条件 …;
*/
-- 需求:查询员工的姓名、性别和部门名称
-- 隐式内连接
select e.name,e.gender,d.dname from emp e,dept d where e.dep_id=d.did;
select e.name,e.gender,d.dname from emp e,dept d where e.dep_id=d.did and e.name like '猪%';
-- 显式内连接
select e.name,e.gender,d.dname from emp e inner join dept d on e.dep_id=d.did;
select e.name,e.gender,d.dname from emp e inner join dept d on e.dep_id=d.did where e.name like '孙%';
/*
-- 左外连接
SELECT 字段列表 FROM 表1 LEFT [OUTER] JOIN 表2 ON 条件 LEFT [OUTER] JOIN 表3 ON 条件…;
-- 右外连接
SELECT 字段列表 FROM 表1 RIGHT [OUTER] JOIN 表2 ON 条件 RIGHT [OUTER] JOIN 表3 ON 条件…;
*/
-- 需求:查询所有员工的和员工的部门信息
-- 左外连接
select * from emp e left join dept d on e.dep_id=d.did;
-- 右外连接
select * from emp e right join dept d on e.dep_id=d.did;
/*
单行单列:作为条件值,使用 = != > <等进行条件判断
SELECT 字段列表 FROM 表 WHERE 字段名 = (子查询);
多行单列:作为条件值,使用 in 等关键字进行条件判断
SELECT 字段列表 FROM 表 WHERE 字段名 in (子查询);
多行多列:作为虚拟表
SELECT 字段列表 FROM (子查询) WHERE 条件;
*/
use db2;
-- 需求1:查询工资高于猪八戒的员工信息
select * from emp where salary>(select salary from emp where NAME='猪八戒');
-- 需求2:查询 '财务部' 和 '市场部' 所有的员工信息
select * from emp where dep_id in (select did from dept where dname in ('财务部','市场部'));
-- 需求3:查询入职日期是 '2011-11-11' 之后的员工信息和部门信息
select * from (select * from emp inner join dept d on d.did = emp.dep_id) a where a.join_date>'2011-11-11';
事务
数据库的事务是一种机制,指的是把一组SQL操作看成一个整体,在执行的过程中要么同时成功,要么同时失败。
DROP TABLE IF EXISTS account;
-- 创建账户表
CREATE TABLE account(
id int PRIMARY KEY auto_increment,
name varchar(10),
money double(10,2)
);
-- 添加数据
INSERT INTO account(name,money) values('张三',1000),('李四',1000);
UPDATE account set money = 1000;
select * from account;
-- 李四的窗口------------
-- 演示事务操作
-- 需求:张三向李四借500元
-- 开启事务,一旦开启事务了,在没有提交事务或者回滚事务时,所做的所有操作都是临时操作。
start transaction ; begin;
-- 1 李四账户-500
update account set money=money-500 where name='李四';
select * from abc;
-- 2 张三账户+500
update account set money=money+500 where name='张三';
-- 提交事务
commit ;
-- 回滚事务
rollback ;
事务四大特征
原子性A | 事务是不可分割的最小操作单位,要么同时成功,要么同时失败 |
一致性C | 数据库要一直处于一致的状态,事务的运行不会改变数据库原本的一致性约束。 |
隔离性I | 多个事务之间是不能被相互影响。 |
持久性D | 事务一旦提交或回滚,它对数据库中的数据的改变就是永久的 |
