文章目录
1、约束条件
在项目开发,我们要对表的数据进行管理(比如说从业务逻辑的角度,保证数据的正确性), 比如有一个字段叫 email, 要求是唯一的。为了达到这个效果,mysql提供一种机制来保证这些数据的正确性,就是表的约束
表的约束有5种: 主键(primary key)、not null (非空)、unique(唯一约束), 外键约束, check约束[在mysql中,支持check的语法,但是本身并不生效]
1.1、主键(primary key)
用于唯一的标示表行的数据,当定义主键约束后,该列不能重复, 一般来说,mysql中的每张表都会有一个primary key, 用于唯一标识一条记录. 而且这个primary 所在的列是整数类型
特点:
1、主键的约束效果是not null+unique
2、innodb表有且只有一个主键,但是该主键可以是联合主键
mysql> create table t8(id int primary key, name varchar(10));
Query OK, 0 rows affected (1.43 sec)
mysql> desc t8;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int | NO | PRI | NULL | |
| name | varchar(10) | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.20 sec)
1.2、not null
如果在列上定义了not null,那么当插入数据时,必须为列提供数据
mysql> create table t9(id int primary key,name varchar(10) not null);
Query OK, 0 rows affected (1.83 sec)
mysql> desc t9;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int | NO | PRI | NULL | |
| name | varchar(10) | NO | | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> insert into t9 values(1,null); # 必须插入数据并且不能是null
ERROR 1048 (23000): Column 'name' cannot be null
# not null 可以设置默认值
mysql> create table t9(x int not null default 111);
Query OK, 0 rows affected (1.18 sec)
mysql> insert into t9 values();
Query OK, 1 row affected (0.17 sec)
mysql> desc t9;
+-------+------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+------+------+-----+---------+-------+
| x | int | NO | | 111 | |
+-------+------+------+-----+---------+-------+
1 row in set (0.04 sec)
1.3、unique
当定义了唯一约束后,该列值是不能重复的
mysql> create table t10(id int primary key,email varchar(20) unique); # email字段不可以重复
Query OK, 0 rows affected (1.34 sec)
mysql> insert into t10 values(1,'123@qq.com');
Query OK, 1 row affected (0.17 sec)
mysql> insert into t10 values(2,'123@qq.com');
ERROR 1062 (23000): Duplicate entry '123@qq.com' for key 't10.email'
# 联合唯一
mysql> create table server(
-> id int,
-> name varchar(10),
-> ip varchar(15),
-> port int,
-> unique(ip,port),
-> unique(name)
-> );
Query OK, 0 rows affected (1.27 sec)
mysql> insert into server values (1,"web1","10.10.0.11",8080);
Query OK, 1 row affected (0.16 sec)
mysql> insert into server values (2,"web2","10.10.0.11",8081);
Query OK, 1 row affected (0.11 sec)
mysql> insert into server values (3,"web3","10.10.0.11",8081);
ERROR 1062 (23000): Duplicate entry '10.10.0.11-8081' for key 'server.ip'
补充:
not null 和 unique的化学反应 => 会被识别成表的主键
mysql> create table test1(id int,name varchar(10) not null unique);
Query OK, 0 rows affected (1.48 sec)
mysql> create table test2(id int,name varchar(10) unique);
Query OK, 0 rows affected (1.78 sec)
mysql> desc test1;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int | YES | | NULL | |
| name | varchar(10) | NO | PRI | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql> desc test2;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id | int | YES | | NULL | |
| name | varchar(10) | YES | UNI | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
1.4、check
check只是做语法的校验,而没有真正的生效
mysql> create table t11(id int primary key,sal float check(sal>100 and sal<900));
Query OK, 0 rows affected (0.71 sec)
1.5、外键
用于定义主表和从表之间的关系: 外键约束要定义在从表上,主表则必须具有主键约束或是unique约束,当定义外键约束后,要求外键列数据必须在主表的主键列存在或是为null
# 基本语法
foreign key (字段名) references 主表(列)
# 假设学生和班级表(一个学生属于一个班级,一个班级拥有多个学生)
# 先创建被关联表(班级)
mysql> create table class(
id int primary key,
name varchar(12) unique
);
Query OK, 0 rows affected (0.63 sec)
# 创建两个班级
mysql> insert into class values(1,'班级1');
Query OK, 1 row affected (0.18 sec)
mysql> insert into class values(2,'班级2');
Query OK, 1 row affected (0.13 sec)
# 再创建关联表
mysql> create table student(
id int primary key,
name varchar(12),
class_id int,
foreign key student(class_id) references class(id) on update cascade on delete cascade # 设置外键
);
Query OK, 0 rows affected (1.10 sec)
mysql> insert into student values(1,'zhangsan',1); # class_id为1存在,正常插入
Query OK, 1 row affected (0.19 sec)
mysql> insert into student values(2,'lisi',5); # class_id为5不存在,插入失败
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`db01`.`student`, CONSTRAINT `student_ibfk_1` FOREIGN KEY (`class_id`) REFERENCES `class` (`id`) ON DELETE CASCADE ON UPDATE CASCADE)
2、关系数据库中表与表的三种关系
表1 foreign key 表2
则表1的多条记录对应表2的一条记录,即多对一
利用foreign key的原理我们可以制作两张表的多对多,一对一关系
多对多:
表1的多条记录可以对应表2的一条记录
表2的多条记录也可以对应表1的一条记录
一对一:
表1的一条记录唯一对应表2的一条记录,反之亦然
分析时,我们先从按照上面的基本原理去套,然后再翻译成真实的意义,就很好理解了
2.1、一对一
一对一关系: 表1的一条记录唯一对应表2的一条记录,例如用户基本信息和用户详细信息
# 先创建被关联表(用户基本信息表)
mysql> create table user(
id int primary key,
name varchar(20)
);
Query OK, 0 rows affected (0.69 sec)
# 插入两个用户
mysql> insert into user values(1,'zhangsan');
Query OK, 1 row affected (0.19 sec)
mysql> insert into user values(2,'lisi');
Query OK, 1 row affected (0.21 sec)
# 再创建关联表(用户详细信息表)
mysql> create table detail(
id int primary key,
phone char(11),
addr varchar(50),
u_id int,
foreign key detail(u_id) references user(id) on update cascade on delete cascade
);
Query OK, 0 rows affected (0.92 sec)
# 两个用户的具体信息(一对一,外键字段一一对应)
mysql> insert into detail values(1,110,'zhangsan的地址',1);
Query OK, 1 row affected (0.09 sec)
mysql> insert into detail values(2,120,'lisi的地址',2);
Query OK, 1 row affected (0.24 sec)
2.2、多对一或者一对多
多对一关系: 左边表的多条记录对应右边表的唯一一条记录
说明:
1、先确立关系
2、找到多的一方,把关联字段写在多的一方
需要注意的:
1.先建被关联的表,保证被关联表的字段必须唯一
2.在创建关联表,关联字段一定保证是要有重复的
案例参考【外键】章节
2.3、多对多
多对一关系: 多条记录对应多条记录,需要建立中间表,例如书与作者
书和作者(创建book和author两张表)
要把book_id和author_id设置成联合唯一
联合唯一: unique(book_id,author_id)
多对多: 一个作者可以写多本书,一本书也可以有多个作者,双向的一对多,即多对多
# 先创建被关联表(书籍表)
mysql> create table book(
id int primary key auto_increment,
name varchar(10),
price float(3,2)
);
Query OK, 0 rows affected, 1 warning (1.02 sec)
# 再创建关联表(作者表)
mysql> create table author(
id int primary key auto_increment,
name char(5)
);
Query OK, 0 rows affected (0.97 sec)
# 最后创建中间表
mysql> create table author2book(
id int primary key auto_increment,
book_id int not null,
author_id int not null,
unique(book_id,author_id),
foreign key(book_id) references book(id) on delete cascade on update cascade,
foreign key(author_id) references author(id) on delete cascade on update cascade
);
Query OK, 0 rows affected (1.52 sec)
mysql> insert into book(name,price) values('三国演义',9.9), ('西游记',9.5),('红楼梦',5),('水浒传',7.3);
Query OK, 4 rows affected (0.30 sec)
mysql> insert into author(name) values('allen'),('lily'),('tom'),('tank'),('lucy');
Query OK, 5 rows affected (0.20 sec)
mysql> insert into author2book(book_id,author_id) values(1,1),(1,4),(2,1),(2,5),(3,2),(3,3),(3,4),(4,5);
Query OK, 8 rows affected (0.88 sec)
mysql> select * from author2book; # 中间表保存具体关联的数据
+----+---------+-----------+
| id | book_id | author_id |
+----+---------+-----------+
| 1 | 1 | 1 |
| 2 | 1 | 4 |
| 3 | 2 | 1 |
| 4 | 2 | 5 |
| 5 | 3 | 2 |
| 6 | 3 | 3 |
| 7 | 3 | 4 |
| 8 | 4 | 5 |
+----+---------+-----------+
8 rows in set (0.00 sec)
3、单表查询
3.1、准备数据表及数据
# 创建表
create table employee(
id int not null unique auto_increment,
name varchar(20) not null,
sex enum('male','female') not null default 'male', # 大部分是男的
age int(3) unsigned not null default 28,
hire_date date not null,
post varchar(50),
post_comment varchar(100),
salary double(15,2),
office int, # 一个部门一个屋子
depart_id int
);
# 查看表结构
mysql> desc employee;
+--------------+-----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-----------------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| name | varchar(20) | NO | | NULL | |
| sex | enum('male','female') | NO | | male | |
| age | int unsigned | NO | | 28 | |
| hire_date | date | NO | | NULL | |
| post | varchar(50) | YES | | NULL | |
| post_comment | varchar(100) | YES | | NULL | |
| salary | double(15,2) | YES | | NULL | |
| office | int | YES | | NULL | |
| depart_id | int | YES | | NULL | |
+--------------+-----------------------+------+-----+---------+----------------+
10 rows in set (0.07 sec)
# 插入记录
# 三个部门: 教学,销售,运营
mysql> insert into employee(name,sex,age,hire_date,post,salary,office,depart_id) values
('allen','male',18,'20170301','teacher',7300.33,401,1), # 以下是教学部
('luly','male',78,'20150302','teacher',1000000.31,401,1),
('tom','male',81,'20130305','teacher',8300,401,1),
('jack','male',73,'20140701','teacher',3500,401,1),
('lilei','male',28,'20121101','teacher',2100,401,1),
('hanmeimei','female',18,'20110211','teacher',9000,401,1),
('zhangsan','male',18,'19000301','teacher',30000,401,1),
('lisi','male',48,'20101111','teacher',10000,401,1),
('wangwu','female',48,'20150311','sale',3000.13,402,2), # 以下是销售部门
('张三','female',38,'20101101','sale',2000.35,402,2),
('李四','female',18,'20110312','sale',1000.37,402,2),
('王五','female',18,'20160513','sale',3000.29,402,2),
('赵六','female',28,'20170127','sale',4000.33,402,2),
('用户1','male',28,'20160311','operation',10000.13,403,3), # 以下是运营部门
('用户2','male',18,'19970312','operation',20000,403,3),
('用户3','female',18,'20130311','operation',19000,403,3),
('用户4','male',18,'20150411','operation',18000,403,3),
('用户5','female',18,'20140512','operation',17000,403,3);
Query OK, 18 rows affected (0.34 sec)
注意:
select * from t1 where 条件 group by 分组字段
1、分组只能查询分组字段,要想查看其余的利用聚合函数
2、聚合函数的分类: count,min,max,avg,group_concat,sum等
3、模糊匹配: 用like关键字
select * from t1 where name like '%al%'; # %表示任意字符
select * from t1 where name like 'd__l'; # 一个下划线表示一个字符,两个下划线就表示两个字符
4、拷贝表:
create table t2 select * from t1;
create table t2 select * from t1 where 1=2 ;
3.2、查询语法
SELECT 字段1,字段2... FROM 表名
WHERE 条件
GROUP BY field
HAVING 筛选
ORDER BY field
LIMIT 限制条数
3.3、简单查询
# 简单查询
SELECT id,name,sex,age,hire_date,post,post_comment,salary,office,depart_id
FROM employee;
SELECT * FROM employee;
SELECT name,salary FROM employee;
# 避免重复DISTINCT
SELECT DISTINCT post FROM employee;
# 通过四则运算查询
SELECT name, salary*12 FROM employee;
SELECT name, salary*12 AS Annual_salary FROM employee;
SELECT name, salary*12 Annual_salary FROM employee;
# 定义显示格式
CONCAT() 函数用于连接字符串
SELECT CONCAT('姓名: ',name,' 年薪: ', salary*12) AS Annual_salary
FROM employee;
CONCAT_WS() 第一个参数为分隔符
SELECT CONCAT_WS(':',name,salary*12) AS Annual_salary
FROM employee;
3.4、where约束
where字句中可以使用:
1、比较运算符: > < >= <= <> !=
2、between 80 and 100 值在10到20之间
3、in(80,90,100) 值是80或90或100
4、like 'al%'
可以是%或_,
%表示任意多字符
_表示一个字符
like 'al__n'
5、逻辑运算符: 在多个条件直接可以使用逻辑运算符 and or not
# 1:单条件查询
SELECT name FROM employee WHERE post='sale';
# 2:多条件查询
SELECT name,salary FROM employee WHERE post='teacher' AND salary>10000;
# 3:关键字BETWEEN AND
SELECT name,salary FROM employee WHERE salary BETWEEN 10000 AND 20000;
SELECT name,salary FROM employee WHERE salary NOT BETWEEN 10000 AND 20000;
# 4:关键字IS NULL(判断某个字段是否为NULL不能用等号,需要用IS)
SELECT name,post_comment FROM employee WHERE post_comment IS NULL;
SELECT name,post_comment FROM employee WHERE post_comment IS NOT NULL;
SELECT name,post_comment FROM employee WHERE post_comment=''; 注意''是空字符串,不是null
ps:
执行
update employee set post_comment='' where id=2;
再用上条查看,就会有结果了
# 5:关键字IN集合查询
SELECT name,salary FROM employee WHERE salary=3000 OR salary=3500 OR salary=4000 OR salary=9000 ;
SELECT name,salary FROM employee WHERE salary IN (3000,3500,4000,9000) ;
SELECT name,salary FROM employee WHERE salary NOT IN (3000,3500,4000,9000) ;
# 6:关键字LIKE模糊查询
通配符’%’
SELECT * FROM employee WHERE name LIKE 'al%';
通配符’_’
SELECT * FROM employee WHERE name LIKE 'al__';
3.5、having过滤
having和where语法上是一样的
select * from employee where id>15;
select * from employee having id>15;
where和having的区别
# 执行优先级从高到低: where > group by > 聚合函数 > having >order by
1、Where 是一个约束声明,使用Where约束来自数据库的数据,Where是在结果返回之前起作用的(先找到表,按照where的约束条件,从表(文件)中取出数据),Where中不能使用聚合函数
2、Having是一个过滤声明,是在查询返回结果集以后对查询结果进行的过滤操作(先找到表,按照where的约束条件,从表(文件)中取出数据,然后group by分组,如果没有group by则所有记录整体为一组,然后执行聚合函数,然后使用having对聚合的结果进行过滤),在Having中可以使用聚合函数。
3、where的优先级比having的优先级高
4、having可以放到group by之后,而where只能放到group by 之前。
3.6、group by分组查询
大前提: 可以按照任意字段分组,但分完组后,只能查看分组的那个字段,要想取的组内的其他字段信息,需要借助函数
单独使用GROUP BY关键字分组
select post from employee group by post;
注意: 我们按照post字段分组,那么select查询的字段只能是post,想要获取组内的其他相关信息,需要借助函数
GROUP BY关键字和group_concat()函数一起使用
select post,group_concat(name) from employee group by post; # 按照岗位分组,并查看组内成员名
select post,group_concat(name) as emp_members FROM employee group by post;
GROUP BY与聚合函数一起使用
select post,count(id) as count from employee group by post; # 按照岗位分组,并查看每个组有多少人
强调:
一般相同的多的话就可以分成一组(一定是有重复的字段)
3.7、order by查询排序
按单列排序
SELECT * FROM employee ORDER BY salary;
SELECT * FROM employee ORDER BY salary ASC;
SELECT * FROM employee ORDER BY salary DESC;
按多列排序: 先按照age排序,如果年纪相同,则按照薪资排序
SELECT * from employee ORDER BY age,salary DESC;
1、select * from employee order by salary; # 如果不指定,默认就是升序
2、select * from employee order by salary asc;
3、select * from employee order by salary desc;
# 先按照年龄升序,当年龄相同的太多,分不清大小时,在按照工资降序
4、select * from employee order by age asc, salary desc;
3.8、使用聚合函数查询
先from找到表
再用where的条件约束去表中取出记录
然后进行分组group by,没有分组则默认一组
然后进行聚合
最后select出结果
示例:
select count(*) from employee;
select count(*) from employee where depart_id=1;
select max(salary) from employee;
select min(salary) from employee;
select avg(salary) from employee;
select sum(salary) from employee;
select sum(salary) form employee WHERE depart_id=3;
3.9、where的补充(使用正则表达式查询)
1、select * from employee where name regexp '^all'; # 匹配以all开头的员工信息
2、select * from employee where name regexp 'en$'; # 匹配以en结尾的员工信息
3、select * from employee where name regexp 'n{1,2}'; # 匹配name里面包含1到2个n的员工信息
小结: 对字符串匹配的方式
where name = 'allen';
where name like 'zhangs%';
where name regexp 'si$';
3.10、limit限制查询的记录数
1、select * from employee limit 3; # 打印前三条
2、像这样表示的: 指的是从哪开始,往后取几条 (这样的操作一般用来分页)
select * from employee limit 0,3;
select * from employee limit 3,4;
select * from employee limit 6,3;
select * from employee limit 9,3;
3、select * from employee order by id desc limit 3; # 查看后三条
分页显示,每页5条
select * from employee limit 0,5; # 第一页
select * from employee limit 5,5; # 第二页
select * from employee limit 10,5; # 第三页
3.11、关键字的执行优先级
关键字的执行优先级:
from
where
group by
having
select
distinct
order by
limit
具体:
1、找到表: from
2、拿着where指定的约束条件,去文件/表中取出一条条记录
3、将取出的一条条记录进行分组group by,如果没有group by,则整体作为一组
4、如果有聚合函数,则将组进行聚合
5、将4的结果过滤: having
6、查出结果: select
7、去重
8、将6的结果按条件排序: order by
9、将7的结果限制显示条数