SQL学习笔记

116 阅读14分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第9天,点击查看活动详情

本文是 狂神说 Java:MySQL 最新教程通俗易懂 的课程笔记

前言

学校突然要期中检测🤦‍♀️,摸鱼的summer表示很无奈,🙄,那就简单了解一下数据库,后续再慢慢补充,期末再补充吧🧑‍💻

操作数据库语句

操作数据库

MySQL的数据库语言分为四大类:

  • DDL:数据定义语言
  • DML:数据操作语言
  • DQL:数据查询语言
  • DCL:数据控制语言

创建数据库

create DATABASE `mydata`

删除数据库

DROP DATABASE `mydata`

使用数据库

USE `mydata`

查看所有数据库

SHOW DATABASES;

数据库的常见列类型

数值类型大小(字节)
tinyint1
smallint2
mediumint3
int4
bigint8
float4
double8
decimal字符串形势

关于对int(M)这种的简单理解:

再写sql的时候,我们可能会见到int(1),int(4)这种,你可能只是知道,这里面的数字并不代表存储的宽度

我的理解:这个长度,其实就是为了告诉sql数据库,这个字段的存储数据的宽度为M位数,即使你不是M位数,只要不超过这个int类型,其实都是可以正常存储的

字符类型说明
char定长字符串,范围0-255
varchar变长字符串,范围在0-65535
tinytext小文本,范围2^8-1
text文本串,范围5=2^16-1
日期说明
data日期格式:YYY_MM_DD
time时间格式:HH:mm:ss
datetime时间格式:YY_MM_DD HH:mm:ss
timestamp时间戳
year

数据库的字段属性

字段属性含义
UNSIGNED无符号的
ZEROFILL零填充位数
AUTO_INCREASE自增
NOT NULL是否可空
DAFAULT默认值
COMMENT注释,可选

一个业务型数据库必须有这些字段

字段说明
id一般是主键
version乐观锁
is_delete伪删除
gmt_create创建时间
gmt_update修改时间

创建数据库表

CREATE TABLE `表名`(
	`字段名` 列类型 [属性] [索引] [注释],
    ....
)[引擎][字符集][注释]

下面举一个列子

CREATE TABLE `student`(
	`id` INT(4) NOT NULL ANUT_INCREASEMENT 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;
    # ENGINE=INNODB default charset=utf8;意思是,使用INNODB引擎,使用默认的utf-8字符集

注意:

  • 每一句,我们用逗号(,)进行分隔,最后一行可以没有
  • 数据库不使用驼峰法,所以一般是使用小写字母或者下划线分隔,首字母可以大写
  • Table名和字段名用反引号括起来
  • 字符串,尽量使用单引号
  • 一个表只会有一个主键,他跟在语句的最后面

查看表的结构

-- 查看结构
DESC student;
DESCRIBE student;# 描述这个表,就是查看这个表的结构

-- 查看创建数据库的语句
SHOW Create database mydata;

-- 查看建表语句
SHOW create table student;

常见数据库引擎

  • InnoDB
  • MyISAM
特点InnoDBMyISAM
事务支持支持不支持
数据行锁定支持不支持
外键约束支持不支持
全文索引不支持支持
表空间大约是MyISAM的两倍较小

总结:

InnoDB:他的安全性比较高,事件处理,可以进行多表多用户操作

MyISAM:节约空间,速度较快

修改删除数据表

修改表的名称rename

-- Alter table 数据表名 Rename 改为的数据表名
ALTER Table student Rename student1;
-- alter:本来就有更改的意思

增加表的字段add

-- Alter table 数据表名 Add 字段名 列类型
ALTER Table student Add age INT(11);

修改表的字段约束(列类型)modify

-- Alter table 数据表名 Modify 字段名 列类型
Alter table student Modify age Varchar(10); 

修改表的字段名change

Alter table student Change age age1 Int(1)

modifychange的区别

  • modify:其实是对约束的修改,对列类型的修改
  • change:类似于重命名,是对字段名进行改变

删除表的字段drop

Alter Table student drop age1;

删除表

Drop table if exists student

MySQL的数据管理

外键

删除有外键的表,必须先删除引用这个表的表

现在我们让student表也拥有grageid,年级字段,我们新建一个表,表示年级,年级字段引用年级表的gradeid字段

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 '年级ID',
    `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;

还有一种为已经创建的表生成外键的方式

# constraint:约束
Alter Table `student`
	ADD constraint `FK_gradeid` Foreign Key(`gradeid`) References `grade`(`gradeid`)

其实你大概理解一下:增加一个约束FK_gradeid,外键是gradeid,依赖是grade这个表的gradeid这个属性

DML语言

数据操作语言

  • 插入INSERT
  • 更新UPDATE
  • 删除DELETE

插入insert into

举例:

往grade表里面插入

-- INSERT INTO `Table名` (`字段名`) Values(值)
INSERT INTO `grade`(`gradename`)Values('大四')

其实他非常的语义化:Table里面插入values值,因为值可能不是一个

插入多个值

INSERT INTO `grade`(`gradeid`) Values('大一'),('大二')

但是如果你是插入一个完整的记录的话

INSERT INTO `grade` VALUES (3,'大四'),(4,'大一')

我们其实可以不用写字段名,这样他会自已一个一个的慢慢匹配

INSERT INTO `grade` VALUES(4,'大二')

更新update

更新表里面的值

-- 更新
-- UPDATE `数据表` SET `字段`=值 where `字段`=值
-- 更新student表里面的id=20的字段的name值
UPDATE `student` SET `name`='summer' where 'id'=20 

当然了,我们也可以一次更新多个值

UPDATE `student` SET `sex`='男','email'='summer@qq.com' where 'id' = 20

这里面我们就可以一次设置多个值,每个值之间,用逗号(,)分开

操作符含义
=等于
<>或者!=不等于
BETWEEN...AND...在范围内
>,<,>=,<=大于,小于,大于等于,小于等于
AND
OR
NOT否定

删除deletetruncate

删除数据

只删除一条

-- delete from `数据表` WHERE `字段`= 值
delete from `grade` where `gradeid` = 1

清空整个表,但是,它里面的字段啥的,都是保留着的

-- TRUNCATE Table `数据表名`
truncate Table `grade`

区别:

deletetruncate

  • dlelete:这个在我的理解,他就是将你那条记录删了
  • truncate:就是将所有的记录删了,但是字段不会变

deletedrop

  • drop:他这个其实都是在删除字段,就是那个表里面的列
  • delete:他删除的是记录,就是表里面的行

DQL查询数据

DQL:数据查询语言

  • 数据库最核心的语言
  • 所有的查询都是用select查询
  • 简单和复杂的查询都能写
  • 使用频率最高的语句

首先先建立一些必须要的数据表,并插入一些字段

-- 创建学生表
drop table if exists `student`;
create table `student`(
    `studentno` int(4) not null comment '学号',
    `loginpwd` varchar(20) default null,
    `studentname` varchar(20) default null comment '学生姓名',
    `sex` tinyint(1) default null comment '性别,0或1',
    `gradeid` int(11) default null comment '年级编号',
    `phone` varchar(50) not null comment '联系电话,允许为空',
    `address` varchar(255) not null comment '地址,允许为空',
    `borndate` datetime default null comment '出生时间',
    `email` varchar (50) not null comment '邮箱账号允许为空',
    `identitycard` varchar(18) default null comment '身份证号',
    primary key (`studentno`),
    unique key `identitycard`(`identitycard`),
    key `email` (`email`)
) engine=myisam default charset=utf8;

-- 创建年级表
drop table if exists `grade`;
create table `grade`(
    `gradeid` int(11) not null auto_increment comment '年级编号',
    `gradename` varchar(50) not null comment '年级名称',
    primary key (`gradeid`)
) engine=innodb auto_increment = 6 default charset = utf8;

-- 创建科目表
drop table if exists `subject`;
create table `subject`(
    `subjectno`int(11) not null auto_increment comment '课程编号',
    `subjectname` varchar(50) default null comment '课程名称',
    `classhour` int(4) default null comment '学时',
    `gradeid` int(4) default null comment '年级编号',
    primary key (`subjectno`)
) engine = innodb auto_increment = 19 default charset = utf8;

-- 创建成绩表
drop table if exists `result`;
create table `result`(
    `studentno` int(4) not null comment '学号',
    `subjectno` int(4) not null comment '课程编号',
    `examdate` datetime not null comment '考试日期',
    `studentresult` int (4) not null comment '考试成绩',
    key `subjectno`(`subjectno`)
) engine = innodb default charset = utf8;

-- 插入学生数据
insert into `student` (`studentno`, `loginpwd`, `studentname`, `sex`, `gradeid`, `phone`, `address`, `borndate`, `email`, `identitycard`) values
    (1000, '123456', '张伟', 0, 2, '13800001234', '北京朝阳', '1980-1-1', 'text123@qq.com', '123456198001011234'),
    (1001, '123456', '赵强', 1, 3, '13800002222', '广东深圳', '1990-1-1', 'text111@qq.com', '123456199001011233');

-- 插入成绩数据
insert into `result`(`studentno`, `subjectno`, `examdate`, `studentresult`) values
    (1000, 1, '2013-11-11 16:00:00', 85),
    (1000, 2, '2013-11-12 16:00:00', 70),
    (1000, 3, '2013-11-11 09:00:00', 68),
    (1000, 4, '2013-11-13 16:00:00', 98),
    (1000, 5, '2013-11-14 16:00:00', 58);

-- 插入年级数据
insert into `grade` (`gradeid`, `gradename`) values
    (1, '大一'), (2, '大二'), (3, '大三'), (4, '大四'), (5, '预科班');

-- 插入科目数据
insert into `subject`(`subjectno`, `subjectname`, `classhour`, `gradeid`) values
    (1, '高等数学-1', 110, 1),
    (2, '高等数学-2', 110, 2),
    (3, '高等数学-3', 100, 3),
    (4, '高等数学-4', 130, 4),
    (5, 'C语言-1', 110, 1),
    (6, 'C语言-2', 110, 2),
    (7, 'C语言-3', 100, 3),
    (8, 'C语言-4', 130, 4),
    (9, 'Java程序设计-1', 110, 1),
    (10, 'Java程序设计-2', 110, 2),
    (11, 'Java程序设计-3', 100, 3),
    (12, 'Java程序设计-4', 130, 4),
    (13, '数据库结构-1', 110, 1),
    (14, '数据库结构-2', 110, 2),
    (15, '数据库结构-3', 100, 3),
    (16, '数据库结构-4', 130, 4),
    (17, 'C#基础', 130, 1);

基本查询

查询所有字段

select * from student;

查询指定字段,并且使用别名

也就是,我们展现出来的,是我们使用的别名

select studentno as '学号',studentname as '学生姓名' from `student`

这时候其实我们展示出来的是

学号学生姓名
1000张伟
1001赵强

查询被连接的字符串

select concat("姓名+学号:",studentname,studentno) AS '新名字' from `student`

其实他的意思,也就是,将本来是两()个字段可以合并(concat)为一个

新名字
姓名+学号:张伟1000
姓名+学号:赵强1001

去重

对结果去重

其实我觉得,就是对当前表的这一列进行去重,返回去重过后的字段

-- select distinct `列名称` from `表名称`
select distinct studentno from `student`

查询表达式

select 100*3 AS RES
RES
300

select后面的表达式可以包括:

  • 文本
  • 列(字段)
  • null
  • 函数
  • 计算表达式
  • 系统遍历

where条件语句

就像介绍的那样,其实我们的where其实就是一个判断语句

查询成绩在95~100

select * from `result` where studentresult Between 95 and 100 

他这个是会返回一整条的记录

查询不是1000号学生的成绩

select * from `result` where not studentno = 1000

模糊查询

运算符描述
IS NULL为空
IS NOT NULL非空
LIKE匹配
IN在集合内

当我们使用LIKE这个去进行匹配的时候,其实我感觉,就是在使用正则类似

  • %:相当于*
  • _:相当于?

查询学生表中所有姓张的学生

select `studentno`,`studentname` from `student` where `studentname` like '张%'

查询在指定集合里面的学生

select `studentno`,`studentname` from `student` where `studentname` in (1000,1003,1023)

联表查询

例子:查询所有参加了考试的同学(学号,姓名,科目,分数)

flowchart LR
    A[连接查询] --> B[内连接]
    B-->D[相当于查询A表和B表的交集部分]
    A-->C[外连接]
    C-->E[左外查询]
    E-->E1[查询左表的所有数据以及两表交集的部分数据]
    C-->F[右外查询]
    F-->F1[查询右表的所有数据以及两表交集的部分数据]
    C-->G[自连接]
    G-->G1[当前表与自身的连接查询以及自连接必须使用表别名]

内连接

查询A和B的交集部分数据

  1. 隐式内连接

    select 字段列表 from1,表2 where 筛选条件
    
  2. 显式内连接

    select 字段列表 from1 inner join2 on 筛选条件
    

例题:

查询每个员工的姓名以及相关联的部门名称

表结构:emp,dept

筛选条件:emp.dep_id = dept.id

select emp.dep_id,dept.id from `emp`,`dept` where emp.dep_id = dept.id

显式:

select emp.dep_id,dept.id from `emp` inner join `dept` on emp.dep_id = dept.id

也可以使用表别名,as

select e.dep_id,d.id 
from `emp` as e 
inner join `dept` as d 
on e.dep_id = d.id

外连接

查询emp表的所有数据,和对应的部门信息

注意:因为这里需要我们emp的所有数据,所以我们就不能简单地只是用内连接,因为,内连接包含的可能不是全部

左外连接
select e.*,d.id 
from emp as e -- 左表
left outer join dept as d -- 右表
on e.dept_id = d.id
右外连接
select e.*,d.id
from dept as d -- 左
right outer join emp as e
on e.dept_id = d.id

自连接

自连接:就是自己连接自己,也就是将一张表连续查询多次

select 字段名
from1 as 别名
join1 as 别名2
on 条件

子查询一定需要起别名

查询员工及其所诉领导的名字

因为员工和领导都属于员工,都在员工表里面,每个员工有一项manager_id记录领导的id

select a.name,b.name
from emp as a
join emp as b
on a.manage_id = b.id

查询所有员工及其领导姓名

select a.name,b.name
from emp as a -- 左
left outer join emp as b -- 右
on a.manage_id = b.id

等值连接

where:等值连接

查询员工名,工种号,工种名

select e.last_name,e.job_id,j.job_title
from emp as e, job as j
where e.job_id = j.job_id

加筛选条件

查询有奖金的员工名和部门名

select last_name,department_name
from emp as e,department as d
where e.department_id = d.department_id
and e.commission_pct is not null -- 非空
-- 因为之前已经有了一个where,所以,不可以出现多个,下面那个就使用and

查询城市名中第二个字符为o的部门名和城市名

select department_name,city
from department as d,location as l
where d.location_id = l.location.id
and city like '_o%'

做题思路:

  • 分析需求,确定我们需要查询的是那些字段
    • 从那些表查询数据
    • 入谷坡存在多张表的查询,先从两张表的查询开始
  • 确定使用那种查询
    • 确定判断条件

查询学生所属的年级

select studentno,studentname,gradename
From student -- 左表
Inner join grade -- 右表
on student.gradeid = grade.gradeid

查询参加"高等数学-4"考试的同学信息(学号,学生,姓名,科目名,分数)

select s.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 r.subjectno = sub.subjectno
    WHERE subjectname = '高等数学-4';

分组和排序

SQLselect完整语法

select [all|distinct] {*|table.*|[table.]field[as alias],...}
from table [as table_alias],....
[left|right|inner join table2]
[where ...]
[group by ...]
[having ...]
[order by ...]
[limit]

分组:

我的理解就是:你按照什么进行分组,这样当我们出现分组相同的时候,就只会显示一个

SELECT `subject`.subjectname,SUM(`subject`.classhour) AS '总课时' FROM `subject`,grade
WHERE `subject`.gradeid = grade.gradeid
GROUP BY `subject`.subjectname
having subjectname LIKE '%高等数学%

其实听他就是按照subject.name来进行分组

having:其实就是对分组完成以后的,在进行一次筛选

排序:

SELECT studentno, studentresult
    FROM result
    ORDER BY studentresult DESC;

这边我们使用order by进行排序

DESC:降序

ASC:升序

SELECT s.studentno,s.studentname,sub.subjectname,r.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
	WHERE sub.subjectname LIKE '%高等数学%' 
	ORDER BY r.studentresult DESC

一定要严格注意,顺序,也就是limit是放在最后的

子查询

简单说:其实就是查询里面嵌套着查询

  • 子查询必须是在圆括号里
  • 子查询不可以使用order by,但是可以使用group by,可以起到类似效果
  • 子查询不可以使用聚合函数
SELECT column_name [, column_name ]
FROM   table1 [, table2 ]
WHERE  column_name OPERATOR
      (SELECT column_name [, column_name ]
      FROM table1 [, table2 ]
      [WHERE])

查询 “高等数学-4” 的所有考试结果(学科,科目编号,成绩),降序排列。

SELECT studentno, subjectno, studentresult
FROM result
WHERE subjectno = (
    SELECT subjectno FROM `subject`
    WHERE subjectname = '高等数学-4'
)
ORDER BY studentresult DESC;

其实我的理解就是

  • 首先我们发现result里面没有科目这一栏,所以需要和subject联合起来

  • 也就是,我们需要在subject里面找到高等数学-4这个

    select studentno from subject
    WHERE subjectname = '高等数学-4'
    
  • 然后将两个连起来

为什么这边使用的是subjectno呢?

因为这两个表的这列的字段是相同的

MySQL常见函数

聚合函数

函数名描述
count计数
sum求和
avg平均值
min最小值
max最大值

参考链接:

狂神说 Java:MySQL 最新教程通俗易懂

MySQL 学习笔记 - 鸭梨的博客 (alexsun.top)

连接查询(多表查询)——MySQL_master cat的博客-CSDN博客_连接查询和多表查询