数据库之约束条件、表关系及单表查询

tech2022-08-02  127

文章目录

1、约束条件1.1、主键(primary key)1.2、not null1.3、unique1.4、check1.5、外键 2、关系数据库中表与表的三种关系2.1、一对一2.2、多对一或者一对多2.3、多对多 3、单表查询3.1、准备数据表及数据3.2、查询语法3.3、简单查询3.4、where约束3.5、having过滤3.6、group by分组查询3.7、order by查询排序3.8、使用聚合函数查询3.9、where的补充(使用正则表达式查询)3.10、limit限制查询的记录数3.11、关键字的执行优先级

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,sum3、模糊匹配: 用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 值在1020之间 3in(80,90,100) 值是8090100 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的结果限制显示条数
最新回复(0)