数据库查缺补漏

#是一个占位符

使用占位符可以防止sql的注入,#{}会将传入的数据当成一个字符串,会对自动传入的数据加一个双引号,${}会将传入的数据直接显示生成在sql

$是拼接符(参数)

${}:传入的内容会直接拼接,不会加上引号,可能存在sql注入的安全隐患

%是搜索的通配符,Window 中是*

mysql中#{}和${}的区别详解_Mysql_脚本之家 (jb51.net)

初识数据库

介于前端和后端之间的数据库,是******核心所在。

为什么学习数据库:

岗位需求;技术大框架中的不可或缺的”数据存储“需要;网络安全

什么是数据库:

数据库(DB,DataBase)

概念:数据仓库,软件,安装在操作系统(window、linux、mac…)之上!SQL,可以存储大量的数据。500万!

作用:存储数据,管理数据

数据库分类:

关系型数据库:(SQL)

  • MySQL、Oracle、SqIServer、DB2、SQLlite
  • 通过表和表之间,行和列之间的关系进行数据的存储,

非关系型数据库:(NoSQL)Not Only

  • Redis,MongDB
  • 非关系型数据库,对象存储,通过对象的自身的属性来决定。

DBMS(数据库管理系统)

  • 数据库的管理软件,科学有效的管理我们的数据。维护和获取数据,
  • MySQL,数据库管理系统

MySQL 简介

MySQL 是一个关系型数据库管理系统

🔴最流行的开源数据库是MySQL

历史沿革:瑞典 MySql AB 公司

如今:属于 Oracle 旗下产品

安装建议:

尽量不使用 exe ,注册表,卸载麻烦

建议使用使用压缩包

安装 MySQL

MySQL :: Download MySQL Community Server

谷歌搜索:mysql community

  1. 解压后放到电脑环境目录下

  2. 配置环境变量,按 Win 键搜索,环境变量bin目录放入

  3. mysql的一级目录下,新建mysql 配置文件 my.ini

    1. [mysqld]
      # 设置3306端口号
      port=3306
      
      # 设置MySQL的安装目录
      basedir=D:\\software\\an qr\\mysql-8.0.31-winx64
      
      # 设置MySQL数据库的数据存放目录
      datadir=D:\\software\\an qr\\mysql-8.0.31-winx64\\data
      
      # 启动mysql后将skip-grant-tables前面的#删掉
      skip-grant-tables
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24



      4. 在`bin`目录下,以管理员身份启动`CMD`

      1. ```mysql
      # 安装 mysql,显示 Service successfully installed. 即为成功
      mysqld -install

      # 出现 data 文件夹,初始化数据文件
      mysqld --initialize-insecure --user=mysql

      # 启动 mysql
      net start mysql
      net stop mysql

      # 进入 mysql
      mysql -u root -p
      mysql -u root -proot
      mysql -u root -p紧紧跟着密码

      # 进入记得修改密码,可以注释掉跳过密码了,然后重启
      net stop mysql
      net start mysql

连接数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
mysql -uroot -proot  -- 命令行连接

-- sql 的注释是
flush privileges; -- 刷新权限

---------------------------
所有的语句使用`;`结尾
show databases; -- 查看所有的数据库

use mysql; -- 切换数据库
Database changed

show tables; -- 查看数据表中所有的表

describe student; -- 显示数据库中所有表的信息

create database westos; -- 创建一个数据库

exit; -- 退出连接

-- 单行注释(SQL 的本来的注释)

/* (sql 的单行注释)
hello
hi
*/

操作数据库

简单操作数据库

操作数据库 > 操作数据库中的表 > 操作数据库中表的数据
mysql关键字不分区大小写

1
2
3
4
5
6
7
8
9
10
11
12
-- 创建数据库
CREATE DATABASE IF NOT EXISTS westos

-- 删除数据库
DROP DATABASE IF EXISTS westos

-- 使用数据库
-- tab键的上而,如果你的表名或者字段名是一个特殊字符,就需要带``
USE `school`

-- 查看所有的数据库
SHOW DATABASES;

对比SQLyog的可视化历史记录查看
固定的语法或关键字必须要记住!

数据库的列类型

数值

  • tinying,十分大小数据,1 个字节
  • smallint,较小的数据,2 个字节
  • mediumint,中等大小的数据,3 个字节
  • int,标准的整数,4 个字节
  • bigint,较大的数据,8 个字节
  • float,浮点数,4 个字节
  • double,浮点数,4 个字节
  • decimal,字符串形式的浮点数,金融计算的时候,一般是使用 decimal

字符串

  • char,字符串固定大小的,0~244
  • varchar,可变字符串,0~65535(常用的变量 String)
  • tinytext,微型文本,2^8-1
  • text,文本串,2^16-1,保存大文本

时间日期

java.util.Date

  • date,YYYY-MM-DD,日期格式
  • time,HH:mm:ss,时间格式
  • datetime,YYYY-MM-DD HH:mm:ss,最常用的时间格式
    • 小写的 h 是 12 小时制,大写的 H 是 24 小时制
  • timestamp,时间戳,1970.1.1 到现在的毫秒数!也较为常用!
  • year,年份表示

null

  • 没有值,未知
  • 注意:不要使用 NULL 进行计算,结果为 NULL

字段属性

UNsigned

  • 无符号整数
  • 声明的该列不能声明未负数

zerofill:

  • 0 填充的
  • 不足的位数,使用 0 来填充,int(3),5 — 005

自增

  • 通常理解为自增,自动在上一条记录的基础上+1(默认)
  • 通常用来设计唯一的主踺~index,必须是整数类型
  • 可以自定义设主键自增的起始值和步长

非空 Null not null

  • 假设设置为 not null,如果不给他赋值,就会报错
  • NUII 如果不填写值,默认就是nu旧

拓展:听听就好

1
2
3
4
5
6
7
8
9
/ *
每一个表,都必须存在以下五个字段

id 主键
`version` 乐观锁
is_delete 伪删除
gmt_create 创建时间
gmt_update 修改时间
*/

创建数据库表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
show databases;
-- 目标:创建一个 school 数据库
-- 创建学生表(列,字段)使用 SQL 创建
-- 学号 int,登录密码 varchar(20).出生日期(datatime),家庭住址,email

-- 注意点,使用英文括号,表的名称和字段使用``,避免识别为关键字
-- AUTO_INCREMENT 自增
-- 字符串使用单引号括起来!
-- 所有语句后面加英文的逗号,最后一个不用加
-- PARMARY KEY 主键,一般一个表只有一个唯一的主键

CREATE DATABASE school;
USE school;
CREATE TABLE IF NOT EXISTS `student`(
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
`name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密码',
`sex` VARCHAR(2) NOT NULL DEFAULT '女' COMMENT '性别',
`birthday` DATETIME DEFAULT NULL COMMENT '出生日期',
`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',
`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8

格式

1
2
3
4
5
6
CREATE DATABASE [IF NOT EXISTS] `表明`(
`字段名` 列类型 [属性] [索引] [注释],
`字段名` 列类型 [属性] [索引] [注释],
……
`字段名` 列类型 [属性] [索引] [注释],
)[表类型][字符集设置][注释]

常用命令

1
2
3
SHOW CREATE DATABASE school -- 查看创建数据库的语句
SHOW CREATE TABLE student -- 查看数据库表的定义语句
DESC student -- 显示表的结构

数据表的类型

1
2
3
4
5
-- 关于数据库引擎
/*
INNODB 默认使用~
MYISAM 早些年使用的
*/
MYISAM INNODB
事务支持 不支持 支持
数据行锁定 不支持 支持
外键约束 不支持 支持
全文索引 支持 不支持
表空间的大小 较小 较大,约为 2 倍

常规使用操作

  • MYISAM,节约空间,速度较快
  • INNODB,安全性高,事务的处理,多表多用户操作

在物理空间存在的位置:

所有的数据库文件都存在 date 目录下

本质还是文件的存储

MySQL 引擎在物理文件上的区别

  • INNODB,在数据库表中只有一个*.frm文件,以及上级目录下的ibdata1 文件
  • MYISAM 对应的文件
    • *.frm表结构的定义文件
    • *.MYD数据文件(data)
    • *.MYI索引文件

设置数据库表的字符集编码

1
CHARSET=utf8

不设置的话,会是mysql 默认的字符集编码(不支持中文)

my.ini中配置默认的编码

1
character-set-server=utf8

修改删除表

修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-- 修改表名:ALTER TABLE 旧表名 RENAME SA 新表名
-- teacher 改为 teacher1
ALTER TABLE teacher RENAME AS teacher1

-- 增加表的字段:ALTER TABLE 表名 ADD 字段名 列属性
ALTER TABLE teacher1 ADD age INT(11)

-- 修改表的字段(重命名,修改约束!)
-- ALTER TABLE 表名 MODIFY 字段名 列属性
ALTER TABLE teacher1 MODIFY age VARCHAR(11) -- 修改约束

-- ALTER TABLE 表名 CHANGE 旧名字 新名字 列属性[]
ALTER TABLE teacher1 CHANGE age age1 INT(1) -- 字段重命名

-- 删除表的字段:ALTER TABLE 表名 DROP 字段名
ALTER TABLE teacher1 DROP age1

删除

1
2
-- 删除表(存在再删除)
DROP TABLE IF EXISTS teacher1

所有的创建和删除尽量加上判断,以免报错

注意点:

  • 反引号`` 字段名,使用这个包裹
  • 注释: -- /**/
  • 关键字大小写不敏感,建议使用小写(大写看不明白单词意思)
  • 所有符合全部使用英文!

MySQL 的数据管理

外键(了解即可)

方式一:在创建表的时候,增加约束(麻烦,比较复杂)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-- 学生表的 gradeid 字段,要去引用年级表的 gradeid
-- 定义外键key
-- 给这个外键添加约束(执行引用) reference 引用
CREATE TABLE IF NOT EXISTS `student`(
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
`name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密码',
`sex` VARCHAR(2) NOT NULL DEFAULT '女' COMMENT '性别',
`birthday` DATETIME DEFAULT NULL COMMENT '出生日期',
`gradeid` INT(10) NOT NULL COMMENT '学生的年级',
`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',
`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY(`id`),
KEY `FK_gradeid` (`gradeid`),
CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade` (`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8
  • 删除有外键关系的表的时候,必须要先删除引用别人的表(从表),再删除被引用的表(主表)

  • 以上的操作都是物理外键,数据库级别的外键,我们不建议使用!(避免数据库过多造成困扰)

  • 最佳实践:

    • 数据库就是单纯的表,只用来存数据,只有行(数据)和列(字段)
    • 我们想要使用多张表的数据,想使用外键(程序去实现)

其实这个话是老生常谈,很多人在工作中确实也不会使用外键,包括在阿里的JAVA规范中也〖强制〗不得使用外键与级联,一切外键既念必须在应用层解决

但是呢,洵问他们原因,大多是这么回答的
每次做DELETE或者UPDATE必须考虑外键约束会导致开发的时候很痛苦,测过极为不方便

DML 语言(全部记住)

数据库的意义:数据存储,数据管理

DML 语言:数据库操作语言

  • insert
  • update
  • delete

添加 insert

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- 插入语句(添加)
-- insert into 表名([字段名1,字段名2,字段名3]) values('值1'),('值2'),('值3'),...)
INSERT INTO `grade` (`gradename`) VALUES('大四')

-- 由于主键自增我们可以省略字段名,但是它会一一匹配,所以参数必须包含所有字段的值
INSERT INTO `grade` VALUES (3, '大三')

-- 插入多个字段
INSERT INTO `grade`(`gradename`) VALUES('大一'),('大二')

INSERT INTO `student`(`name`) VALUES('张三')

INSERT INTO `student`(`name`,`pwd`,`sex`) VALUES('张三','aaaaaa','男')

INSERT INTO `student`(`name`,`pwd`,`sex`)
VALUES('李四','aaaaaa','男'),('王五','bbbbbb','男')

语法:insert into 表名([字段名1,字段名2,字段名3]) values(‘值1’),(‘值2’),(‘值3’),…)

注意事项:

  1. 字段和字段之间使用,英文逗号隔开
  2. 字段是可以省略的,但是后面的值必须要一一对应,不能少
  3. 可以同时插入多条数据,VALUES后面的值,需要使用,隔开即可VALUES(),(),...

修改 update

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-- update 修改谁 (条件) set 原来的值=新值

-- 修改学员的名字,把 id = 1 的这个人的名字改为张三
update `student` set `name`='张三' where id = 1;

-- 不指定条件的情况下,改动所有的表
update `student` set `name`='猫龙'

-- 语法:
-- update 表名 set colnum_name = value where [条件]

-- 修改多个属性,逗号隔开
update `student` set `name`='狗龙',`email`='208329492@qq.com' where id = 1;

-- 语法:
-- update 表名 set colnum_name = value,[colnum_name = value,,] where [条件]

条件:where 字句 运算符 id 等于某个值,在某个区间内修改

操作符会返回布尔值

操作符 含义 范围 结果
= 等于
<> 或 != 不等于
>
<
>=
<=
BETWEEN…AND… 闭合空间内
AND
OR
1
2
3
-- 多个条件定位数据
-- 把性别为女姓名为华的这个人的名字改为“小树”
update `student` set `name`='小树' where `name`='华' and sex = '女'

语法:update 表名 set colnum_name =value,[colnum_name =value] where [条件]

注意:

  • colnum_name 是数据库的列,尽量带上``
  • 条件,筛选的条件,如果没有指定,则会修改所有的列
  • value,是一个具体的值,也可以是一个变量
  • 多个设置的属性之间,使用英文逗号隔开
1
update `student` set `birthday` = current_time where `name`='小树' and sex='男'

删除 delete

语法:delete from 表名 [where 条件]

1
2
3
4
5
-- 删除数据(避免这样写,有专门的删库方法)
delete from `student`

-- 删除指定数据
delete from `student` where id = 1;

TRUNCATE

作用:完全清空一个数据库表,表的结构和索引约束不会变

1
2
-- 清空 student 表
truncate `student`

delete 和 truncate 的区别

  • 相同点:都能删除数据,都不会删除表的结构
  • 不同
    • truncate 重新设置,自增列,计数器会清零
    • truncate 不会影响事务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
-- 测试 delete 和 truncate 的区别
-- 查看数据库
SHOW DATABASES;
-- 使用数据库
use `mysql`;
-- 查看数据表


-- 创建表格
create table `test`(
`id` int(4) not null auto_increment,
`coll` varchar(20)not null,
primary key(`id`)
)engine=innodb default charset=utf8

-- 插入数据
insert into `test`(`coll`) values('1'),('2'),('3');

-- 删除表,不会影响自增
delete from `test`;

-- 删除表,自增归零
truncate table `test`;

了解即可:delete 删除的问题,重启数据库,现象

  • innodb 自增列会从 1 开始(存在内存当中,断点即失)
  • myisam 继续从上一个自增量开始(存在文件中不会丢失)

DQL 查询数据(最重点)

DQL

Date Query Language :数据查询语言

  • 所有的查询操作都用它,select 选择

  • 简单查询,复杂查询

  • :warning:数据库中最核心的语言

  • 使用频率最高

指定查询字段

  • 数据库 school

    • grade

    • result

    • student

    • subject

1
2
3
4
5
6
7
8
9
10
11
12
13
-- 查询全部的学生,select 字段 from 表
select * from student
-- 查询全部的成绩
selsct * from result

-- 查询指定字段
select `StudentNo`,`StudentName` from student

-- 别名,给结果起名字,AS
select `StudentNo` AS 学号,`StudentName` AS 姓名 from student AS s

-- 函数 concat(a,b)
select concat('姓名:',StudentName) AS 新名字 from student

语法:select 字段,,,from 表

有的时候,列名字不明朗,可以起别名

字段名 AS 别名,表名 AS 别名

去重 distinct:

作用:去除 select 查询出来的结果中重复的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
select * from result -- 查询全部的成绩

-- 查询一下有哪些同学参加了考试
select `StudentNo` from result

-- 发现重复数据,result 数据表中的 StudentNo 列的重复数据通过 distinct 去重
select distinct `StudentNo` from result

-- 查看系统的版本
select version()
select 100*3-1 AS 计算结果
-- 查询自增的步长
select @@auto_increment_increment

-- 给所有学生成绩加一分
select `StudentNo`,`StudentResult +1` AS '提分后' from result

数据库中的表达式:文本值,列,Null,函数,计算表达式,系统变量

select 表达式

where 条件字句

作用:检索数据库中符合条件的值

逻辑运算符:

搜索的条件由一个或多个表达式组成,结构布尔值

运算符 语法 描述
and & a and b a&&b 逻辑与,两个为真结果为真
or ` `
Not ! not a !a 逻辑非,真为假,假为真

尽量使用英文字母

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- 查询学生的成绩
select studentNo,`studentResult` from result

-- 查询学生的成绩在 95-100 之间的
select studentNo,`studentResult` from result where studentResult>=95 and studentResult<=100

select studentNo,`studentResult` from result where studentResult>=95 && studentResult<=10

-- 模糊查询(区间)
select studentNo,`studentResult` from result where between 95 and 100

-- 除了 1000 号学生之外学生的成绩
select studentNo,`studentResult` from result where studentNo!=1000

select studentNo,`studentResult` from result where not studentNo = 1000

比较运算符

模糊查询

运算符 语法 描述
is null a is null 如果操作符为 null,则结果为真
is not null a is not null 如果操作符为 not null,则结果为真
between a between b and c a 在 b 和 c 之间,结果为真
like a like b SQL 匹配,a 匹配到 b,结果为真
in a in(a1,a2,a3) 假设 a 在 a1……其中的一个值中,结果为真
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
-- 查询姓刘的同学
-- like(% 是 0 到任意一个字符)(_ 是一个字符)
select `studentNo`,`studentName` from `student`
where studentName like '刘%'

-- 查询姓刘的同学,名字后面只有一个字的
select `studentNo`,`studentName` from `student`
where studentName like '刘_'

-- 查询姓刘的同学,名字后面只有两个字的
select `studentNo`,`studentName` from `student`
where studentName like '刘__'

-- 查询名字中间有嘉字的同学 %嘉%
select `studentNo`,`studentName` from `student`
where studentName like '%嘉%'

-- --------- in(具体的一个或多个值) ------------
-- 查询 1001 1002 1003 号学员信息
select `studentNo`,`studentName` from `student`
where studentNo in (1001,1002,1003);

-- 查询在北京的学员信息
select `studentNo`,`studentName` from `student`
where `adress` in ('北京')

-- ---------- null not null -------------
-- 查询地址为空的学生
select `studentNo`,`studentName` from `student`
where `adress`=''
select `studentNo`,`studentName` from `student`
where `adress` or `adress` is null

-- 查询有出生日期的同学,is not null 不为空
select `studentNo`,`studentName` from `student`
where `borndate` is not null

-- 查询没有出生日期的同学,is null 为空
select `studentNo`,`studentName` from `student`
where `borndate` is null

联表查询

img

JOIN 对比:

操作符名称 描述
Inner join 如果表中有至少一个匹配,则返回行
left join 从左表中返回所有的行,即使右表中没有匹配
right join 从右表中返回所有的行,即使左表中没有匹配
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/*
连接查询
如果需要多张数据表的数据进行查询,则可通过连接运算符实现多个查询
- 内连接 inner join
查询两个表中的结果集中的交集
- 外连接 outer join
- 左外连接 left join
以左表作为基准,右表来一一匹配,匹配不上的,返回左表的记录,右表以NULL填充
- 右外连接 right join
以右表作为基准,左表来一一匹配,匹配不上的,返回右表的记录,左表以NULL填充
*/

/*
1.分析需求,分析查询的字段来自哪些表
2.确定使用哪种连接查询:7选
3.确定交叉点(这两个表中哪个数据是相同的)
4.判断的条件: 学生表中 studentNo = 成绩表中 studentNo
*/

-- ==========联表查询============
-- Join(表)on (判断的条件) 连接查询
-- where 等值查询
SELECT s.studentno, studentname, subjectno, studentresult
FROM student AS s
INNER JOIN result AS r
WHERE s.`studentno` = r.`studentno`


-- right join
SELECT s.studentno, studentname, subjectno, studentresult
FROM student AS s
RIGHT JOIN result AS r
ON r.`studentno` = s.`studentno`

-- left 左连接(查询所有同学,不考试的也会查出来)
SELECT s.studentno, studentname, subjectno, studentresult
FROM student s
LEFT JOIN result r
ON s.`studentno` = r.`studentno`

-- 查缺考的同学(左连接应用场景)
SELECT s.studentno, studentname, subjectno, studentresult
FROM student s
LEFT JOIN result r
ON s.`studentno` = r.`studentno`
WHERE studentresult IS NULL

-- 思考题:查询参加了考试的同学信息(学号,学生姓名,科目名,分数)
SELECT s.`studentno`, `studentname`, `subjectname`, `studentresult`
FROM student AS s,
INNER JOIN result AS r,
ON s.`studentno` = r.`studentno`
INNER JOIN `subject` AS sub
ON sub.subjectno = r.subjectno

自连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/*
自连接:
数据表与自身进行连接

需求:从一个包含栏目ID,栏目名称和父栏目ID的表中
查询父栏目名称和其它子栏目名称
*/

-- 创建表并插入数据

CREATE TABLE `school`.`category`( `categoryid` INT(3) NOT NULL COMMENT 'id',
`pid` INT(3) NOT NULL COMMENT '父id 没有父则为1',
`categoryname` VARCHAR(10) NOT NULL COMMENT '种类名字',
PRIMARY KEY (`categoryid`)
) ENGINE=INNODB CHARSET=utf8 COLLATE=utf8_general_ci;

INSERT INTO `school`.`category` (`categoryid`, `pid`, `categoryname`) VALUES ('2', '1', '信息技术');
INSERT INTO `school`.`CATEGOrY` (`categoryid`, `pid`, `categoryname`) VALUES ('3', '1', '软件开发');
INSERT INTO `school`.`category` (`categoryid`, `PId`, `categoryname`) VALUES ('5', '1', '美术设计');
INSERT INTO `School`.`category` (`categoryid`, `pid`, `categorynamE`) VALUES ('4', '3', '数据库');
INSERT INTO `school`.`category` (`CATEgoryid`, `pid`, `categoryname`) VALUES ('8', '2', '办公信息');
INSERT INTO `school`.`category` (`categoryid`, `pid`, `CAtegoryname`) VALUES ('6', '3', 'web开发');
INSERT INTO `SCHool`.`category` (`categoryid`, `pid`, `categoryname`) VALUES ('7', '5', 'ps技术');

-- 编写SQL语句,将栏目的父子关系呈现出来(父栏目名称,子栏目名称)
-- 核心思想:把一张表看成两张一模一样的表,然后将这两张表连接查询(自连接)
SELECT a.categoryname AS '父栏目', b.categoryname AS '子栏目'
FROM category AS a, category AS b
WHERE a.`categoryid` = b.`pid`

-- 思考题:查询参加了考试的同学信息(学号,学生姓名,科目名,分数)
SELECT s.studentno, studentname, subjectname, studentresult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON sub.subjectno = r.subjectno

-- 查询学员及其所属的年级(学号,学生姓名,年级名)
SELECT studentno AS 学号, studentname AS 学生姓名, gradename AS 年级名称
FROM student s
INNER JOIN grade g
ON s.`gradeid` = g.`gradeid`

-- 查询科目及其所属年级(科目名称,年级名称)
SELECT subjectname AS 科目名称, gradename AS 年级名称
FROM `subject` sub
INNER JOIN grade g
ON sub.gradeid = g.gradeid

-- 查询 数据库结构-1 的所有考试结果(学号,学生姓名,科目名称,成绩)
SELECT s.studentno, studentname, subjectname, studentresult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON r.subjectno = sub.subjectno
WHERE subjectname = '数据库结构-1'

排序和分页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
--  ==========排序===========
/*
语法:order by
order by 语句用于根据指定的列对结果集进行排序
order by 语句默认按照ASC升序对记录进行排序
如果希望按照 降序 对记录进行排序,可以使用 DESC 关键字
*/

-- 查询 数据库结构-1 的所有考试结果(学号,学生姓名,科目名称,成绩)
-- 按成绩降序排序
SELECT s.studentno, studentname, subjectname, studentresult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON r.subjectno = sub.subjectno
WHERE subjectname = '数据库结构-1'
ORDER BY studentresult DESC

分页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
-- ===========分页=============
/*
语法:limit(起始下标, 查询长度) -- 个人觉得这样好理解
limit[pageNo:页码,pageSize:单页面显示条数] -- 原版本
好处:用户体验,网络传输,查询压力
*/
-- 每页显示5条数据
SELECT s.studentno, studentname, subjectname, studentresult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON r.subjectno = sub.subjectno
WHERE subjectname = '数据库结构-1'
ORDER BY studentresult DESC, studentno
LIMIT 0,5

-- 查询 JAVA第一学年 课程成绩前10名并且分数大于80的学生信息(学号,姓名,课程名,分数)
SELECT s.studentno, studentname, subjectname, studentresult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON r.subjectno = sub.subjectno
WHERE subjectname = 'JAVA第一学年'
ORDER BY studentresult DESC
LIMIT 0,10

子查询

where 值是固定的(计算出来的)

本质:在 where 语句中嵌套一个子查询语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
/*============== 子查询 ================
什么是子查询?
在查询语句中的WHERE条件子句中,又嵌套了另一个查询语句
嵌套查询可由多个子查询组成,求解的方式是由里及外;
子查询返回的结果一般都是集合,故而建议使用IN关键字;
*/
-- 查询 数据库结构-1 的所有考试结果(学号,科目编号,成绩),并且成绩降序排列
-- 方法一:使用连接查询
SELECT studentno, r.subjectno, studentresult
FROM result r
INNER JOIN `subject` sub
ON r.`subjectno` = sub.`subjectno`
WHERE subjectname = '数据库结构-1'
ORDER BY studentresult DESC

-- 方法二:使用子查询(执行顺序:由里及外)
SELECT studentno, subjectno, studentresult
FROM result
WHERE subjectno = (
SELECT subjectno FROM `subject`
WHERE subjectname = '数据库结构-1'
)
ORDER BY studentresult DESC

-- 查询课程为 高等数学-2 且分数不小于80分的学生的学号和姓名
-- 方法一:使用连接查询
SELECT s.studentno, studentname
FROM student s
INNER JOIN result r
ON s.studentno = r.studentno
INNER JOIN `subject` sub
ON sub.subjectno = r.subjectno
WHERE subjectname = '高等数学-2' AND studentresult >= 80

-- 方法二:使用连接查询+子查询
-- 分数不小于80分的学生的学号和姓名
SELECT r.studentno, studentname
FROM student s
INNER JOIN result r
ON s.studentno = r.studentno
WHERE studentresult >= 80

-- 在上面SQL基础上,添加需求:课程为 高等数学-2
SELECT r.studentno, studentname
FROM student s
INNER JOIN result r
ON s.studentno = r.studentno
WHERE studentresult >= 80 AND subjectno = (
SELECT subjectno FROM `subject`
WHERE subjectname = '高等数学-2'
)

-- 方法三:使用子查询
-- 分步写简单sql语句,然后将其嵌套起来
SELECT studentno, studentname
FROM student
WHERE studentno IN (
SELECT studentno FROM result
WHERE studentresult >= 80 AND subjectno = (
SELECT subjectno FROM `subject`
WHERE subjectname = '高等数学-2'
)
)


-- 练习题目:查 C语言-1 的前5名学生的成绩信息(学号,姓名,分数)
SELECT s.studentno, studentname, studentresult
FROM student s
INNER JOIN result r
ON s.studentno = r.studentno
INNER JOIN `subject` sub
ON r.subjectno = sub.subjectno
WHERE subjectname = 'C语言-1'
ORDER BY studentresult DESC
LIMIT 0,5


-- 练习题目:使用子查询,查询郭靖同学所在的年级名称
SELECT gradename FROM grade
WHERE gradeid = (
SELECT gradeid FROM student
WHERE studentname = '郭靖'
)

关系模型

image-20221116163711167

主键

对于关系表,有个很重要的约束,就是任意两条记录不能重复。不能重复不是指两条记录不完全相同,而是指***能够通过某个字段唯一区分出不同的记录,这个字段被称为主键。***

例如,假设我们把name字段作为主键,那么通过名字小明小红就能唯一确定一条记录。但是,这么设定,就没法存储同名的同学了,因为插入相同主键的两条记录是不被允许的。

对主键的要求,最关键的一点是:记录一旦插入到表中,主键最好不要再修改,因为主键是用来唯一定位记录的,修改了主键,会造成一系列的影响。

联合主键:

没有必要的情况下,我们尽量不使用联合主键,因为它给关系表带来了复杂度的上升。

主键是关系表中记录的唯一标识。主键的选取非常重要:主键不要带有业务含义,而应该使用BIGINT自增或者GUID类型。主键也不应该允许NULL

外键

students

id name other columns…
1 小明
2 小红

classes

id name other columns…
1 一班
2 二班

但是我们如何确定students表的一条记录,例如,id=1的小明,属于哪个班级呢?

为了表达这种一对多的关系,我们需要在students表中加入一列class_id,让它的值与classes表的某条记录相对应:

id class_id name other columns…
1 1 小明
2 1 小红
5 2 小白

这样,我们就可以根据class_id这个列直接定位出一个students表的记录应该对应到classes的哪条记录。

students表中,通过class_id的字段,可以把数据与另一张表关联起来,这种列称为外键

由于外键约束会降低数据库的性能,大部分互联网应用程序为了追求速度,并不设置外键约束,而是仅靠应用程序自身来保证逻辑的正确性。这种情况下,class_id仅仅是一个普通的列,只是它起到了外键的作用而已。

查询数据

1
2
3
4
5
6
SELECT * FROM <表名>
SELECT * FROM <表名> WHERE <条件表达式>

条件表达式可以用<条件1> AND <条件2>表达满足条件1并且满足条件2

第二种条件是<条件1> OR <条件2>,表示满足条件1或者满足条件2

其他

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#创建一个demo数据库
CREATE DATABASE sql_tutorial;

#查看全部数据库
SHOW DATABASES;

#选择数据库
USE `sql_tutorial`;

#写表格
CREATE TABLE `student`(
`student_id` INT PRIMARY KEY,
`name` VARCHAR(20),
`MAJOR` VARCHAR(20)
)

# PAIMARY KEY 可以用另一种方式写
CREATE TABLE `student`(
`student_id` INT,
`name` VARCHAR(20),
`major` VARCHAR(20),
PRIMARY KEY(`student_id`)
);

#查看表格
DESCRIBE `student`;

#删除表格
DROP TABLE `student`;

#给表格新增属性
ALTER TABLE `student` ADD gpa DECIMAL(3,2);

#删除表格属性
ALTER TABLE `student` DROP COLUMN gpa;

#存入资料
INSERT INTO `student` VALUE(1, '小白', '历史' );
INSERT INTO `student` VALUE(3, '小黑', '生物' );
INSERT INTO `student` VALUE(3, '小绿', NULL );

#搜寻 student 表格中的全部资料
SELECT * FROM `student`;

#指定……不填的话就是 NULL
INSERT INTO `student`(`name`,`major`,`student_id`) VALUE('小兰','英语','4');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
-- constraints 限制 约束

CREATE TABLE `student`(
`student_id` INT,
`name` VARCHAR(20) NOT NULL, #NOT NULL name 属性不能为空
`MAJOR` VARCHAR(20) UNIQUE, #MAJOR 属性必须唯一,UNIQUE
PRIMARY KEY(`student_id`)
);

#修改了表格,先删除表格 DROP TABLE `student`;
然后 Ctrl + Enter

#写表格的时候,设置预设值
`major` VARCHAR(20) DEFAULT '历史', #预设值

#自动补充 1
CREATE TABLE `student`(
`student_id` INT AUTO_INCREMENT,
`name` VARCHAR(20) NOT NULL, #NOT NULL name 属性不能为空
`major` VARCHAR(20) DEFAULT '历史', #预设值
PRIMARY KEY(`student_id`)
);

INSERT INTO `student`(`name`,`major`) VALUE('小白', '英语' );
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-- 修改、删除资料
#先关掉预设的更新模式
SET SQL_SAFE_UPDATES = 0;

#把 major 为英语的改为“英语文学”
UPDATE `student`
SET `major` ='英语文学'
WHERE `major` ='英语' ;

#删掉 student_id 为 4 的那个
DELETE FROM `student`
WHERE `student_id` =4;

#删掉分数小于 60 的
DELETE FROM `student`
WHERE `score` < 60;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
-- 取得资料
#搜寻 student 表格中的全部资料
SELECT * FROM `student`;

#排序,DESC 由高到低
SELECT * FROM `student`
ORDER BY `score` DESC;

# 先根据 score 排序,score 相同则根据 student_id 排序
SELECT * FROM `student`
ORDER BY `score`,`student_id` DESC;

#只要前两笔资料
SELECT * FROM `student`
LIMIT 2;

#找到分数前三低的
SELECT * FROM `student`
ORDER BY `score`;
LIMIT 3;

#找到分数前三高的
SELECT * FROM `student`
ORDER BY `score` DESC;
LIMIT 3;

参考:

【数据库】SQL 3小时快速入门_bilibili(已看)

SQL教程 - 廖雪峰的官方网站 (liaoxuefeng.com)

【狂神说Java】MySQL最新教程通俗易懂(已看)

SQLBolt - Learn SQL - SQL Lesson 2: Queries with constraints (Pt. 1)


© Rabbit 使用 Stellar 创建

✨ 营业:

共发表 56 篇Blog 🔸 总计 123.6k