MySQL表的增删改查(进阶)

MySQL表的增删改查(进阶)

  • 1. 数据库约束
    • 1.1 约束类型
    • 1.2 NULL 约束
    • 1.3 UNIQUE 约束
    • 1.4 DEFAULT 约束
    • 1.5 PRIMARY KEY 约束
    • 1.6 FOREIGN KEY 约束
  • 2. 表的设计
  • 3. 新增
  • 4. 查询
    • 4.1 聚合查询
      • 4.1.1 聚合函数
      • 4.1.2 GROUP BY
      • 4.1.3 HAVING
    • 4.2 联合查询
      • 4.2.1 内连接
      • 4.2.2 外连接
      • 4.2.3 自连接
      • 4.2.4 子查询
      • 4.2.5 合并查询

1. 数据库约束

1.1 约束类型

  • NOT NULL - 指示某列不能存储 NULL 值。
  • UNIQUE - 保证某列的每行必须有唯一的值。
  • DEFAULT - 规定没有给列赋值时的默认值。
  • PRIMARY KEY - NOT NULL 和 UNIQUE 的结合。确保某列(或两个列多个列的结合)有唯一标 - 识,有助于更容易更快速地找到表中的一个特定的记录。
  • FOREIGN KEY - 保证一个表中的数据匹配另一个表中的值的参照完整性。
  • CHECK - 保证列中的值符合指定的条件。对于MySQL数据库,对CHECK子句进行分析,但是忽略CHECK子句。

1.2 NULL 约束

创建表时, 可以指定某列不为空

create table student (
	id int not null, 
	name varchar(20) not null
	);

1.3 UNIQUE 约束

指定某列为唯一的, 不能重复

create table student (
	id int not null, 
	name varchar(20) unique
	);

desc student;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   |     | NULL    |       |
| name  | varchar(20) | YES  | UNI | NULL    |       |
+-------+-------------+------+-----+---------+-------+

1.4 DEFAULT 约束

指定某列为空时, 输出默认值

 create table student (
 	id int not null, 
 	name varchar(20) default 'haha'
 	);

desc student;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   |     | NULL    |       |
| name  | varchar(20) | YES  |     | haha    |       |
+-------+-------------+------+-----+---------+-------+

1.5 PRIMARY KEY 约束

指定某列为主键,

create table student (
	id int primary key, 
	name varchar(20) unique
	);

desc student;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| id    | int(11)     | NO   | PRI | NULL    |       |
| name  | varchar(20) | YES  | UNI | NULL    |       |
+-------+-------------+------+-----+---------+-------+

对于一张表来说, 主键只能有一个.

主键:

  1. 不能为空
  2. 不能重复

自增主键~
对于整数类型的主键,常配搭自增长auto_increment来使用。插入数据对应字段不给值时,使用最大值+1。

id int primary key auto_increment,
create table student (
     id int primary key auto_increment,
     name varchar(20)
    );

desc student;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int(11)     | NO   | PRI | NULL    | auto_increment |
| name  | varchar(20) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+

唯一 ID => 时间戳 + 机房编号 + 机器编号 + 随机因子

1.6 FOREIGN KEY 约束

外键作用于关联其他表的主键唯一键

foreign key [字段名] references [主表()];
create table class (
	id int primary key, 
	name varchar(20));

create table student (
    id int primary key auto_increment,
    name varchar(20),
    classId int,
    foreign key(classId) references class(id)
);

MySQL表的增删改查(进阶)_第1张图片

外键约束就是要求当前表里面的 classId 字段的值, 必须在 class 表的 id 中出现过才可以

2. 表的设计

关于数据库设计~
“数据库设计” 其实就是设计表, 根据当前问题的场景, 需要创建出哪些表, 这些表中应该都是哪些字段, 这些表中的约束都是咋搞

具体思路:
从具体的问题场景中, 先提取出"实体"(对象), 然后再找出多个"实体"之间的关联关系~~

关联关系:

  • 一对一
  • 一对多
  • 多对多

例如, 要表示学生的考试成绩~~
实体(关键性的名词):

  1. 学生
  2. 成绩
  3. 课程

设计表:

  • 学生表(id, name)
    1 张三
    2 李四

  • 课程表(id, name)
    1 语文
    2 数学
    3 英语

  • 成绩表(student_id, course_id, score)

student_id course_id score
1 1 100 (张三的语文是100)
2 1 90 (李四的语文是 90)
1 2 80 (张三的数学是 80)
2 2 90 (李四的数学是 90)

3. 新增

create table user (
	id int primary key, 
	name varchar(20), 
	address varchar(100), 
	phone varchar(11)
	);
	
select * from user;
+----+------+----------+-------+
| id | name | address  | phone |
+----+------+----------+-------+
|  1 | aaa  | address1 | 110   |
|  2 | bbb  | address1 | 110   |
|  3 | ccc  | address1 | 110   |
|  4 | ddd  | address1 | 110   |
+----+------+----------+-------+

insert into user values(1, 'aaa', 'address1', '110');
insert into user values(2, 'bbb', 'address1', '110');
insert into user values(3, 'ccc', 'address1', '110');
insert into user values(4, 'ddd', 'address1', '110');


create table user2(
    id int primary key,
    name varchar(20)
);

insert into user2 id, name from user;

select * from user2;
+----+------+
| id | name |
+----+------+
|  1 | aaa  |
|  2 | bbb  |
|  3 | ccc  |
|  4 | ddd  |
+----+------+

保证 select 查找到的数据的列数和类型能够与待插入的表相匹配~~

4. 查询

4.1 聚合查询

“聚合” 指的是行之间的聚合, 和 “列之间” 无关 ~~

4.1.1 聚合函数

函数 说明
COUNT([DISTINCT] expr) 返回查询到的数据的 数量
SUM([DISTINCT] expr) 返回查询到的数据的 总和,不是数字没有意义
AVG([DISTINCT] expr) 返回查询到的数据的 平均值,不是数字没有意义
MAX([DISTINCT] expr) 返回查询到的数据的 最大值,不是数字没有意义
MIN([DISTINCT] expr) 返回查询到的数据的 最小值,不是数字没有意义

实例:

  • COUNT
select count(*) from [表名];

select count(列) 如果列为空, 就不会计入

  • SUM
select sum(求和字段) from [表名];
  • AVG
select avg(求平均值字段) from [表名];
  • MAX
select max(求最大) from [表名];
  • MIN
select min(求最小) from [表名];

4.1.2 GROUP BY

group by 是针对某一列, 按照列里面的内容, 把这些记录进行分组~~(值相同的在一组)

create table emp (
    id int,
    name varchar(20),
    role varchar(20),
    salary int 
);

insert into emp(id, name, role, salary) values
    (1,'tanglaoshi','teacher', 100),
    (2,'gaolaoshi','teacher', 200),
    (3,'zhenglaoshi','teacher', 300),
    (4,'wenyan','class master', 400),
    (5,'achen','class master', 500),
    (6,'wangzong','market', 600);

 select * from emp;
+------+-------------+--------------+--------+
| id   | name        | role         | salary |
+------+-------------+--------------+--------+
|    1 | tanglaoshi  | teacher      |    100 |
|    2 | gaolaoshi   | teacher      |    200 |
|    3 | zhenglaoshi | teacher      |    300 |
|    4 | wenyan      | class master |    400 |
|    5 | achen       | class master |    500 |
|    6 | wangzong    | market       |    600 |
+------+-------------+--------------+--------+

select role, name, salary from emp group by role;
+--------------+------------+--------+
| role         | name       | salary |
+--------------+------------+--------+
| class master | wenyan     |    400 |
| market       | wangzong   |    600 |
| teacher      | tanglaoshi |    100 |
+--------------+------------+--------+

group by 往往要搭配聚合函数来使用, 如果不是聚合函数, 此时尝试查询一些不重复的类, 可能就不太准确~~

  • 如果不搭配 group by 聚合函数就是针对所有行进行
  • 如果搭配了 group by 就相当于先分组, 然后再进行聚合~~

4.1.3 HAVING

  • 使用 group by 分组之前, 按条件筛选记录, 使用 where
  • 使用 group by 分组之后, 按条件筛选记录, 使用 having

GROUP BY 子句进行分组以后,需要对分组结果再进行条件过滤时,不能使用 WHERE 语句,而需要用 HAVING

4.2 联合查询

实际开发时, 往往需要多表联合查询, 多表查询时对多张表的数据取笛卡尔积:
aaa:

a1 a2
a aa
b bb

bbb:

b1 b2
1 11
2 22

笛卡尔积:

a aa 1 11
a aa 2 22
a aa 2 22
b bb 1 11
b bb 2 22
create table student(
    id int,
    name varchar(20),
    classId int
);

create table class(
    id int,
    class varchar(20)
);

insert into student values
    (1, 'zhangsan', 2),
    (2, 'lisi', 1),
    (3, 'zhaoqiang', 2);

insert into class values
    (1, 'java'),
    (2, 'c');

select student.name from student, class;
+-----------+
| name      |
+-----------+
| zhangsan  |
| zhangsan  |
| lisi      |
| lisi      |
| zhaoqiang |
| zhaoqiang |
+-----------+

 select * from student, class where class.class = 'java' and student.classId = class.id;
+------+------+---------+------+-------+
| id   | name | classId | id   | class |
+------+------+---------+------+-------+
|    2 | lisi |       1 |    1 | java  |
+------+------+---------+------+-------+

select * from student join class on class.class = 'java' and student.classId = class.id;
+------+------+---------+------+-------+
| id   | name | classId | id   | class |
+------+------+---------+------+-------+
|    2 | lisi |       1 |    1 | java  |
+------+------+---------+------+-------+

初始化测试数据:

drop table if exists classes;
drop table if exists student;
drop table if exists course;
drop table if exists score;

create table classes (
	id int primary key auto_increment, 
	name varchar(20), 
	`desc` varchar(100)
	);

create table student (
	id int primary key auto_increment, 
	sn varchar(20),  
	name varchar(20), 
	qq_mail varchar(20),
    classes_id int
    );

create table course(
	id int primary key auto_increment, 
	name varchar(20)
	);

create table score(
	score decimal(3, 1), 
	student_id int, 
	course_id int
	);

insert into classes(name, `desc`) values 
('计算机系2019级1班', '学习了计算机原理、C和Java语言、数据结构和算法'),
('中文系2019级3班','学习了中国传统文学'),
('自动化2019级5班','学习了机械自动化');

insert into student(sn, name, qq_mail, classes_id) values
('09982','黑旋风李逵','[email protected]',1),
('00835','菩提老祖',null,1),
('00391','白素贞',null,1),
('00031','许仙','[email protected]',1),
('00054','不想毕业',null,1),
('51234','好好说话','[email protected]',2),
('83223','tellme',null,2),
('09527','老外学中文','[email protected]',2);

insert into course(name) values
('Java'),('中国传统文化'),('计算机原理'),('语文'),('高阶数学'),('英文');

insert into score(score, student_id, course_id) values
-- 黑旋风李逵
(70.5, 1, 1),(98.5, 1, 3),(33, 1, 5),(98, 1, 6),
-- 菩提老祖
(60, 2, 1),(59.5, 2, 5),
-- 白素贞
(33, 3, 1),(68, 3, 3),(99, 3, 5),
-- 许仙
(67, 4, 1),(23, 4, 3),(56, 4, 5),(72, 4, 6),
-- 不想毕业
(81, 5, 1),(37, 5, 5),
-- 好好说话
(56, 6, 2),(43, 6, 4),(79, 6, 6),
-- tellme
(80, 7, 2),(92, 7, 6);

注意:
多表查询核心就是计算笛卡尔积~~ , 这是一个低效的操作~~

4.2.1 内连接

  1. 查询 “许仙” 同学成绩
    student 表中包含了学生姓名
    score 表中
select * from student, score where student.id = score.student_id and student.name = '许仙';
+----+-------+--------+---------------+------------+-------+------------+-----------+
| id | sn    | name   | qq_mail       | classes_id | score | student_id | course_id |
+----+-------+--------+---------------+------------+-------+------------+-----------+
|  4 | 00031 | 许仙   | xuxian@qq.com |          1 |  67.0 |          4 |         1 |
|  4 | 00031 | 许仙   | xuxian@qq.com |          1 |  23.0 |          4 |         3 |
|  4 | 00031 | 许仙   | xuxian@qq.com |          1 |  56.0 |          4 |         5 |
|  4 | 00031 | 许仙   | xuxian@qq.com |          1 |  72.0 |          4 |         6 |
+----+-------+--------+---------------+------------+-------+------------+-----------+
  1. 查询所有同学的总成绩, 及同学的个人信息
select student.name, student.id, score.student_id, sum(score.score) from student, score where student.id = score.student_id group by student.id;
+-----------------+----+------------+------------------+
| name            | id | student_id | sum(score.score) |
+-----------------+----+------------+------------------+
| 黑旋风李逵      |  1 |          1 |            300.0 |
| 菩提老祖        |  2 |          2 |            119.5 |
| 白素贞          |  3 |          3 |            200.0 |
| 许仙            |  4 |          4 |            218.0 |
| 不想毕业        |  5 |          5 |            118.0 |
| 好好说话        |  6 |          6 |            178.0 |
| tellme          |  7 |          7 |            172.0 |
+-----------------+----+------------+------------------+
  1. 查询所有同学的成绩, 及同学的个人信息
  select student.id, student.name, course.name, score.score from student, course, score where student.id = score.student_id and course.id = score.course_id;
+----+-----------------+--------------------+-------+
| id | name            | name               | score |
+----+-----------------+--------------------+-------+
|  1 | 黑旋风李逵      | Java               |  70.5 |
|  1 | 黑旋风李逵      | 计算机原理         |  98.5 |
|  1 | 黑旋风李逵      | 高阶数学           |  33.0 |
|  1 | 黑旋风李逵      | 英文               |  98.0 |
|  2 | 菩提老祖        | Java               |  60.0 |
|  2 | 菩提老祖        | 高阶数学           |  59.5 |
|  3 | 白素贞          | Java               |  33.0 |
|  3 | 白素贞          | 计算机原理         |  68.0 |
|  3 | 白素贞          | 高阶数学           |  99.0 |
|  4 | 许仙            | Java               |  67.0 |
|  4 | 许仙            | 计算机原理         |  23.0 |
|  4 | 许仙            | 高阶数学           |  56.0 |
|  4 | 许仙            | 英文               |  72.0 |
|  5 | 不想毕业        | Java               |  81.0 |
|  5 | 不想毕业        | 高阶数学           |  37.0 |
|  6 | 好好说话        | 中国传统文化       |  56.0 |
|  6 | 好好说话        | 语文               |  43.0 |
|  6 | 好好说话        | 英文               |  79.0 |
|  7 | tellme          | 中国传统文化       |  80.0 |
|  7 | tellme          | 英文               |  92.0 |
+----+-----------------+--------------------+-------+

4.2.2 外连接

外连接: 左外连接 和 右外连接

-- 左外连接,表1完全显示
select 字段名 from 表名1 left join 表名2 on 连接条件;
-- 右外连接,表2完全显示
select 字段 from 表名1 right join 表名2 on 连接条件;

MySQL表的增删改查(进阶)_第2张图片

4.2.3 自连接

自连接是指在同一张表连接自身进行查询。

  • 显示所有“计算机原理”成绩比“Java”成绩高的成绩信息

成绩信息, 是在 score 表中
课程信息, 是在 course 表中
学生信息, 是在 student 表中

select * from score s1, score s2 where s1.student_id = s2.student_id and s1.course_id = 1 and s2.course_id = 3 and s1.score < s2.score;
+-------+------------+-----------+-------+------------+-----------+
| score | student_id | course_id | score | student_id | course_id |
+-------+------------+-----------+-------+------------+-----------+
|  70.5 |          1 |         1 |  98.5 |          1 |         3 |
|  33.0 |          3 |         1 |  68.0 |          3 |         3 |
+-------+------------+-----------+-------+------------+-----------+

4.2.4 子查询

子查询是指嵌入在其他sql语句中的select语句,也叫嵌套查询

  • 单行子查询:返回一行记录的子查询
    查询与“不想毕业” 同学的同班同学:
select name from student where classes_id = (select classes_id from student where name = '不 想毕业');
+-----------------+
| name            |
+-----------------+
| 黑旋风李逵      |
| 菩提老祖        |
| 白素贞          |
| 许仙            |
| 不想毕业        |
+-----------------+
  • 多行子查询:返回多行记录的子查询
    查询“语文”或“英文”课程的成绩信息
  1. IN关键字:
select * from score where score.course_id in (select id from course where name = '语文' or name = '英文');
+-------+------------+-----------+
| score | student_id | course_id |
+-------+------------+-----------+
|  98.0 |          1 |         6 |
|  72.0 |          4 |         6 |
|  43.0 |          6 |         4 |
|  79.0 |          6 |         6 |
|  92.0 |          7 |         6 |
+-------+------------+-----------+
  1. EXISTS关键字:
 select * from score where exists (select score.course_id from course where (name = '语文' or name = '英文') and course.id = score.course_id);
+-------+------------+-----------+
| score | student_id | course_id |
+-------+------------+-----------+
|  98.0 |          1 |         6 |
|  72.0 |          4 |         6 |
|  43.0 |          6 |         4 |
|  79.0 |          6 |         6 |
|  92.0 |          7 |         6 |
+-------+------------+-----------+

相比于 exists , 还是 in 更好理解

  • in 进行子查询, 就是明确的, 先执行子查询, 子查询执行结束后(存储于内存中), 在进行外查询
  • exists 一般进行外层查询, 一遍进行里层查询 (里层查询执行的次数和外层查询得到的行数是一致的)

exists 查询效率低下, 但是节省内存

4.2.5 合并查询

合并查询, 就是把两个查询结果合并成一个结果

查询id小于3,或者名字为“英文”的课程:

  • union
    该操作符用于取得两个结果集的并集。当使用该操作符时,会自动去掉结果集中的重复行。
select * from course where id < 3 union select * from course where name = '英文';
+----+--------------------+
| id | name               |
+----+--------------------+
|  1 | Java               |
|  2 | 中国传统文化       |
|  6 | 英文               |
+----+--------------------+

-- 或者使用or来实现
select * from course where id<3 or name='英文';
  • union all
    该操作符用于取得两个结果集的并集。当使用该操作符时,不会去掉结果集中的重复行。

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