创建表时, 可以指定某列不为空
create table student (
id int not null,
name varchar(20) not null
);
指定某列为唯一的, 不能重复
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 | |
+-------+-------------+------+-----+---------+-------+
指定某列为空时, 输出默认值
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 | |
+-------+-------------+------+-----+---------+-------+
指定某列为主键,
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 | |
+-------+-------------+------+-----+---------+-------+
对于一张表来说, 主键只能有一个.
主键:
自增主键~
对于整数类型的主键,常配搭自增长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 => 时间戳 + 机房编号 + 机器编号 + 随机因子
外键作用于关联其他表的主键或唯一键
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)
);
外键约束就是要求当前表里面的 classId 字段的值, 必须在 class 表的 id 中出现过才可以
关于数据库设计~
“数据库设计” 其实就是设计表, 根据当前问题的场景, 需要创建出哪些表, 这些表中应该都是哪些字段, 这些表中的约束都是咋搞
具体思路:
从具体的问题场景中, 先提取出"实体"(对象), 然后再找出多个"实体"之间的关联关系~~
关联关系:
例如, 要表示学生的考试成绩~~
实体(关键性的名词):
设计表:
学生表(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) |
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 查找到的数据的列数和类型能够与待插入的表相匹配~~
“聚合” 指的是行之间的聚合, 和 “列之间” 无关 ~~
函数 | 说明 |
---|---|
COUNT([DISTINCT] expr) | 返回查询到的数据的 数量 |
SUM([DISTINCT] expr) | 返回查询到的数据的 总和,不是数字没有意义 |
AVG([DISTINCT] expr) | 返回查询到的数据的 平均值,不是数字没有意义 |
MAX([DISTINCT] expr) | 返回查询到的数据的 最大值,不是数字没有意义 |
MIN([DISTINCT] expr) | 返回查询到的数据的 最小值,不是数字没有意义 |
实例:
select count(*) from [表名];
select count(列) 如果列为空, 就不会计入
select sum(求和字段) from [表名];
select avg(求平均值字段) from [表名];
select max(求最大) from [表名];
select min(求最小) from [表名];
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 子句进行分组以后,需要对分组结果再进行条件过滤时,不能使用 WHERE 语句,而需要用 HAVING
实际开发时, 往往需要多表联合查询, 多表查询时对多张表的数据取笛卡尔积:
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);
注意:
多表查询核心就是计算笛卡尔积~~ , 这是一个低效的操作~~
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 |
+----+-------+--------+---------------+------------+-------+------------+-----------+
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 |
+-----------------+----+------------+------------------+
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 |
+----+-----------------+--------------------+-------+
外连接: 左外连接 和 右外连接
-- 左外连接,表1完全显示
select 字段名 from 表名1 left join 表名2 on 连接条件;
-- 右外连接,表2完全显示
select 字段 from 表名1 right join 表名2 on 连接条件;
自连接是指在同一张表连接自身进行查询。
成绩信息, 是在 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 |
+-------+------------+-----------+-------+------------+-----------+
子查询是指嵌入在其他sql语句中的select语句,也叫嵌套查询
select name from student where classes_id = (select classes_id from student where name = '不 想毕业');
+-----------------+
| name |
+-----------------+
| 黑旋风李逵 |
| 菩提老祖 |
| 白素贞 |
| 许仙 |
| 不想毕业 |
+-----------------+
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 |
+-------+------------+-----------+
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 更好理解
exists 查询效率低下, 但是节省内存
合并查询, 就是把两个查询结果合并成一个结果
查询id小于3,或者名字为“英文”的课程:
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='英文';