数据库(MySQL常用的约束、ER图概述、外键约束的级联删除及级联更新、多表查询)

数据库(MySQL常用的约束、ER图概述、外键约束的级联删除及级联更新、多表查询)_第1张图片

MySQL常用的约束

  • 约束的作用:
    为了保证数据的有效性和完整性
  • MySQL中常用的约束:
    (1). 主键约束(primary key)
    (2). 自增长约束(auto_incrment)加在整数型的字段配和主键约束来使用
    (3). 唯一约束(unique)
    (4). 非空约束(not null)
    (5). 外键约束(foreign key)
    (6). sex ENUM(‘男’,‘女’) – 把一个字段的数据类型设置为枚举类型 也可以起到一种约束的效果
    (7). 非负约束(unsigned)
    例如:这个数据类型 TINYINT 能表示的范围 -128—127
    我添加了这个约束 TINYINT UNSIGNED 范围就是 0----255 也就是没有了负数值

主键约束:被修饰过的字段唯一非空

	注意:一张表只能有一个主键,这个主键可以包含多个字段

	方式1:建表的同时添加约束 格式: 字段名称 字段类型 primary key

	方式2:建表的同时在约束区域添加约束 
		所有的字段声明完成之后,就是约束区域了
		格式: primary key(字段1,字段2)
		
		create table pk01(
			id int,
			username varchar(20),
			primary key (id)
		);
		
		insert into pk01 values(1,'tom');-- 成功
		insert into pk01 values(1,'tom');-- 失败 Duplicate entry '1' for key 'PRIMARY'
		insert into pk01 values(null,'tom');-- 失败  Column 'id' cannot be null
		
		create table pk01(
			id int primary key,
			username varchar(20),
			primary key (id)
		);-- 错误的 一张表只能有一个主键
		
	方式3:建表之后,通过修改表结构添加约束
		create table pk02(
			id int,
			username varchar(20)
		);
		
		alter table pk02 add primary key(字段名1,字段名2..);
		alter table pk02 add primary key(id,username);
		
		insert into pk02 values(1,'tom');-- 成功
		insert into pk02 values(1,'tomcat');-- 成功
		insert into pk02 values(1,'tomcat');-- 失败

	删除主键约束:分两种情况
		情况1: 这个字段,只有主键约束,分两步来删除主键约束
		  第一步:       alter table 表名 drop primary key;  -- 这样只删除了唯一,他还有个非空约束,所以得再删除非空约束
		  第二步:       alter table [表名] modify [列名] varchar(20) null; --修改字段名还为原来的字段 加上null即可
		情况2: 这个字段,是一个int类型字段,既有主键约束,又有自增长约束,那么得先删除自增长约束,在删除主键约束
		   第一步:删除自增长约束,其实就是修改自增长字段名和数据类型还为原来的字段名和类型
			alter table 表名 change 字段名 字段名 数据类型; --删除自增长约束
         第二步:删除主键约束
			alter table 表名 drop primary key;
		   第三步:删除非空约束
		    ALTER TABLE test3 MODIFY sid INT NULL;  -- 就是修改字段值可以为null

自增长约束

(1).要求:
-----1.被修饰的字段类型支持自增. 一般int
-----2.被修饰的字段必须是一个key 一般是primary key
(2).正确案例

CREATE TABLE test10(
    id INT PRIMARY KEY AUTO_INCREMENT, -- 主键自增长约束
    NAME VARCHAR(10),
    age INT
)

INSERT INTO test10(NAME,age) VALUES('aa',20);

DELETE FROM test10 WHERE id=13;

SELECT * FROM test10;

(3).错误案例

create table ai01(
		id varchar(10) auto_increment
	);-- 错误 Incorrect column specifier for column 'id'
	
	create table ai01(
		id int auto_increment
	);-- 错误 Incorrect table definition; there can be only one auto column and it must be defined as a key

唯一约束:

特点:被修饰过的字段唯一,对null不起作用

	方式1:建表的同时添加约束 格式: 字段名称 字段类型 unique
		create table un(
			id int unique,
			username varchar(20) unique
		);
		
		insert into un value(10,'tom');-- 成功
		insert into un value(10,'jack');-- 错误 Duplicate entry '10' for key 'id'
		insert into un value(null,'jack');-- 成功
		insert into un value(null,'rose');-- 成功
		
	方式2:建表的同时在约束区域添加约束 
		所有的字段声明完成之后,就是约束区域了
		unique(字段1,字段值2...)
	方式3:建表之后,通过修改表结构添加约束
		alter table 表名 add unique(字段1,字段2);-- 添加的联合唯一
		alter table 表名 add unique(字段1);-- 给一个添加唯一
		alter table 表名 add unique(字段2);-- 给另一个添加唯一

			create table un01(
				id int,
				username varchar(20)
			); 
			alter table un01 add unique(id,username);
			insert into un01 values(1,'tom');-- 添加成功
			insert into un01 values(1,'jack');-- 添加成功
			insert into un01 values(1,'tom');-- 添加失败  Duplicate entry '1-tom' for key 'id'

非空约束

特点:被修饰过的字段非空

	方式:
		create table nn(
			id int not null,
			username varchar(20) not null
		);
		
		insert into nn values(null,'tom');--  错误的 Column 'id' cannot be null

truncate 清空表 ★

  • 格式:
    truncate 表名; 干掉表,重新创建一张空表
  • truncate和delete from 区别:
    delete属于DML语句 truncate属于DDL语句
    delete逐条删除 truncate干掉表,重新创建一张空表

ER图

在了解外键约束之前得先了解一下表和表之间的关系及ER图

  • 常见表和表之间的关系:
    一对多. 用户和订单 分类和商品
    多对多. 订单和商品 学生和课程
    一对一. 丈夫和妻子
  • ER图可以描述实体于实体之间的关系
    实体用矩形表示
    属性用椭圆表示
    关系用菱形表示
  • 在ER图中有如下四个成分:
    1.矩形框:表示实体,在框中记入实体名。
    2.菱形框:表示联系,在框中记入联系名。
    3.椭圆形框:表示实体或联系的属性,将属性名记入框中。对于主属性名,则在其名称下划一下划线。
    4.连线:实体与属性之间;实体与联系之间;联系与属性之间用直线相连,并在直线上标注联系的类型。
    (对于一对一联系,要在两个实体连线方向各写1; 对于一对多联系,要在一的一方写1,多的一方写N;对于多对多关系,则要在两个实体连线方向各写N,M。)

外键约束

1.一对多关系的外键约束

-- 创建用户表   (一)
create  table user(
	id int primary key auto_increment,
	username varchar(20)
);

-- 创建订单表   (多)
create  table orders(
	id int primary key auto_increment,
	totalprice double,
	user_id int   
);

为了保证数据的有效性和完整性,添加约束(外键约束).
	在多表的一方添加外键约束★
		格式:
			alter table 多表名称 add foreign key(外键名称) references 一表名称(主键);
		例如:
			alter table orders add foreign key(user_id) references user(id);
  • 添加了外键约束之后有如下特点:
    1.主表中不能删除从表中已引用的数据
    2.从表中不能添加主表中不存在的数据
  • 开发中处理一对多:
    在多表中添加一个外键,名称一般为主表的名称_id,字段类型一般和主表的主键的类型保持一致,为了保证数据的有效性和完整性,在多表的外键上添加外键约束即可。
  • 那如果添加了外键后我想删除主表中的数据 怎么办 ?
方式1: 级联删除
ALTER TABLE orders ADD FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE; 
	        	          	然后你就可以删除主表中的数据了
当然你可以级联删除和级联更新 都加上 FOREIGN KEY (sid) REFERENCES stu(sid) ON DELETE CASCADE ON UPDATE CASCADE)
方式2:先把带有外键的多表的数据删除,再删除一表中的数据

2.多对多关系的外键约束

例子:商品和订单
-- 创建商品表
create table product(
	id int primary key auto_increment,
	name varchar(20),
	price double
);

-- 创建中间表
create table orderitem(
	oid int,
	pid int
);

-- 创建订单表   (多)
create  table orders(
	id int primary key auto_increment,
	totalprice double,
	user_id int   
);	
-- 添加外键约束 
alter table orderitem add foreign key(oid) references orders(id);
alter table orderitem add foreign key(pid) references product(id);
  • 开发中处理多对多:
    引入一张中间表,存放两张表的主键,一般会将这两个字段设置为联合主键,这样就可以将多对多的关系拆分成两个一对多了,为了保证数据的有效性和完整性,需要在中间表上添加两个外键约束即可.

字段是枚举类型的约束

特点:值必须是枚举里包含的值

CREATE TABLE test13(
    id TINYINT UNSIGNED, -- 非负约束 
    NAME VARCHAR(10),
    sex ENUM('男','女')   -- enum 枚举类型
)
INSERT INTO test13 VALUES(255,'aa','你');  --添加失败:‘你’不是枚举里的值

非负约束

特点:不能添加负数的值,而且可以增加值的范围。例如:int 类型的范围是 (-2的31次方~2的31次方-1),加上非负约束后,值的范围是(0 ~ 2的32次方-1)

CREATE TABLE test12(
    id TINYINT UNSIGNED, -- 非负约束 
    NAME VARCHAR(10),
    age INT
)

INSERT INTO test12 VALUES(255,'aa',20);

多表查询

  • 多张表查询,要有关联条件
    N张表关联查询 关联条件 得 N-1 个
  • 多表查询的分类:
    先创建两张有关系(一对多关系)的表
	-- 创建用户表   (一)
	create  table user(
		id int primary key auto_increment,
		username varchar(20)
	);
	
	-- 创建订单表   (多)
	create  table orders(
		id int primary key auto_increment,
		totalprice double,
		user_id int   
	);

1.内连接:
------显式内连接:不符合条件的信息,不做展示

SELECT user.*,orders.`id`,orders.`price`,orders.`user_id` FROM USER,orders WHERE user.id=orders.`user_id`;
    
SELECT u.id AS 用户编号,u.`username` 用户名,o.`id` AS 订单号,o.`price` 订单价格,o.`user_id` 外键   FROM USER AS u,orders AS o WHERE u.`id`=o.`user_id`;   

------隐式内连接 inner join on (inner) 可以省略不写

SELECT user.*,orders.* FROM USER INNER JOIN orders ON user.`id`=orders.`user_id`;

2.外连接
----- 左外连接: LEFT 关键字 左边的表中的信息会全部展示,在右边表中没有符合条件的以NULL展示
!特点:LEFT 左边的表中的信息全部展示,没有对应的以null展示

 SELECT user.*,orders.* FROM USER LEFT OUTER JOIN orders ON user.`id`=orders.`user_id`;(OUTER可以省略不写)

----- 右外连接:查询所有订单是属于哪个用户的,所有的订单信息必须展示,这个订单没有对应的用户以NULL展示
!特点:RIGHT 右边的表中的信息全部展示,没有对应的以null展示

SELECT orders.*,user.* FROM USER RIGHT OUTER JOIN orders ON user.`id`=orders.`user_id`;(OUTER可以省略不写)

!!!左外连接和右外连接可以互换
3.子查询
特点:解决 一步查不出来的问题, 一个主查询的查询条件,需要依赖于一个子查询,子查询需要用括号括起来

方式1:采用子查询查询
一.案例演示: 查看用户为张三的订单详情 
    1. 先在 用户表中查询出张三的id
          SELECT user.`id` FROM USER WHERE user.`username`='张三';
	
    2. 拿着张三的id 去订单表中查询 张三的订单信息
          SELECT orders.* FROM orders WHERE orders.`user_id`=3;
             
    3.把以上两步合二为一
	  	  SELECT orders.* FROM orders WHERE orders.`user_id`=(SELECT user.`id` FROM USER WHERE user.`username`='张三');


二.案例演示: 查询出订单的价格大于300的所有用户信息。
   
    1. 先在订单表里面,查出订单价格大于300的订单编号
        SELECT orders.`user_id` FROM orders WHERE orders.`price`>300;
    2. 拿着订单号,去用户表里面查
       SELECT user.* FROM USER WHERE user.`id`=3 OR user.`id`=5;   
    3.把以上两步合二为一
      SELECT user.* FROM USER WHERE user.id IN(SELECT orders.`user_id` FROM orders WHERE orders.`price`>300);

三.案例演示: 查询订单价格大于300的订单信息及相关用户的信息。

   1. 查询订单价格大于300的订单
      SELECT orders.* FROM orders WHERE orders.`price`>300;

   2. 查询用户信息,并且还有他对应的订单信息
     SELECT user.*,lsb.* FROM USER,(SELECT orders.* FROM orders WHERE orders.`price`>300) AS lsb WHERE user.`id`=lsb.user_id;
  
方式2:采用显式内连接查询
         
一.案例演示: 查看用户为张三的订单详情 
            
   1. 先在 用户表中查询出张三的id
          SELECT user.`id` FROM USER WHERE user.`username`='张三';
	
   2. 拿着张三的id 去订单表中查询 张三的订单信息
          SELECT orders.* FROM orders WHERE orders.`user_id`=3;
          SELECT orders.* FROM orders WHERE orders.`user_id`=(SELECT user.`id` FROM USER WHERE user.`username`='张三');
   3. 查看用户为张三的订单详情 要求用户和订单都有展示    
          SELECT user.*,lsb.* FROM USER,(SELECT orders.* FROM orders WHERE orders.`user_id`=(SELECT user.`id` FROM USER WHERE user.`username`='张三')) AS lsb WHERE user.`id`=lsb.user_id;


-- ★★子查询查出来的一张临时表,再要去跟其他表联合查询,注意这个连接条件,中字段重名的问题,你要用别名区分一下


二.案例演示:查询所有订单所包含的商品信息  
  SELECT orders.*,orderitem.* FROM orders LEFT OUTER JOIN orderitem ON orders.`id`=orderitem.`oid`;
   

 SELECT orders.*,product.* FROM orders LEFT OUTER JOIN orderitem ON orders.`id`=orderitem.`oid` LEFT OUTER JOIN product ON orderitem.`pid`=product.`id`;
 

三.案例演示:查询该用户的订单信息,以及订单里面的商品

SELECT user.*,orders.*,product.* FROM USER LEFT OUTER JOIN orders ON user.`id`=orders.`user_id` LEFT JOIN orderitem ON orders.id=orderitem.`oid` LEFT JOIN product ON orderitem.`pid`=product.`id`;
  
  -- 第一步查 用户跟订单 得到一张临时表
  -- 第二步 拿着上步的临时表 跟 中间表 去查,又得到一张临时表
  -- 再拿着第二步的临时表 跟商品表去查

4.自查询

 --    比如:我要查询emp表中 员工姓名 所对应的 上司姓名
         员工      上司
 --     smith     ford
 --     ford      jones
 --     jones     king
 
 -- 把 emp 表  看作两张表 a ,  b
 
 -- 条件 a 表的上司号=b表的员工号
 
 SELECT a.`mgr` AS 上司号,a.ename,b.ename,b.`empno` 员工号 FROM emp AS a,emp AS b WHERE a.`mgr`=b.`empno`;

你可能感兴趣的:(数据库-MySQL)