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

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的结果限制显示条数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值