【大数据学习心得】原创SQL教程(上)

举报
Felix666 发表于 2020/12/27 23:58:29 2020/12/27
【摘要】 本人自己码的数据库基础教程,每个步骤都有说明和代码辅助,大家如果需要可以自行食用(因字数超限分两篇发)。一,认识数据库数据库(Database)是按照数据结构来组织、存储和管理数据的仓库。数据库的一行叫做一条记录,数据库的一列叫做一个字段。数据库分为:关系型数据库和非关系型数据库。   关系型数据库Tips:   (1)关系型数据库中每条记录的字段数量都是相等的。新增一条纪录时,可空字段...

本人自己码的数据库基础教程,每个步骤都有说明和代码辅助,大家如果需要可以自行食用(因字数超限分两篇发)。

一,认识数据库

数据库(Database)是按照数据结构来组织、存储和管理数据的仓库。

数据库的一行叫做一条记录,数据库的一列叫做一个字段

数据库分为:关系型数据库非关系型数据库

    关系型数据库Tips:
  (1)关系型数据库中每条记录的字段数量都是相等的。新增一条纪录时,可空字段如果没有传值会用Null填充,而非空字段如果没有传值则无法生成该条记录。此外,关系型数据库中的记录还受到各字段类型的制约。
  (2)关系型数据库通常用于存储结构化数据,广泛应用于网站后台、数据中台、以及企业的数据管理。
  (3)关系型数据库将数据存放在内存中,因而存储空间较大,读取速度较慢,在不人为删除的情况下,存储永久有效,稳定性较好。

  非关系型数据库Tips:
  (1)非关系型数据库以键值对的形式存储数据,对键和值的数量和类型没有强制要求,相对来说较为自由,当出现个别异常数据时也能很好地处理。此外,非关系型数据库对网络传输的json字符串有较好的支持。
  (2)非关系型数据库通常用于存储非结构化数据,广泛应用于网站中间件、系统缓存、异步处理等技术中。
  (3)非关系型数据库的数据在缓存中,存储空间有限,不适用于存储大量数据,但是读取速度较快。通常数据会有一个过期时间,系统断电也会失效,存储的稳定性不好。

常见的关系型数据库:MySQL、Oracle。

常见的非关系型数据库:Redis、MongoDB。

二,认识MySQL

MySQL 是一个关系型数据库管理软件,是 Oracle 公司的产品。

  • MySQL 是开源的,使用它不需要支付额外的费用。

  • MySQL 支持大型的数据库。可以处理拥有上千万条记录的大型数据库。

  • MySQL 使用标准的 SQL 数据语言形式。

  • MySQL 可以运行于多个系统上,并且支持多种语言。

三,从数据库的命令说起

MySQL 是一个关系型数据库管理软件,它的直接管理对象是数据库,成功连接MySQL 后无论是图形化界面还是命令行也是首先操作的数据库,那么我们就从数据库的命令说起,直接上代码:

-- 查看当前数据库
SHOW DATABASES;

-- 创建一个名为test的数据库
CREATE DATABASE test;

-- 创建数据库的同时指定字符集
CREATE DATABASE test1 DEFAULT CHARSET = utf8;

-- 库不能重名,重名会报错
-- CREATE DATABASE test;
-- > 1007 - Can't create database 'test'; database exists

-- 查看创建库的语句
SHOW CREATE DATABASE test;
-- CREATE DATABASE `test` /*!40100 DEFAULT CHARACTER SET utf8 */

-- 选择当前使用的数据库
USE test;

-- 查看当前所在的库
SELECT DATABASE();

-- 删除数据库
-- 这是程序员届著名的“删库跑路”的命令
-- 一般不是自己建的数据库不要去删除
DROP DATABASE test1;

从数据库的命令初窥SQL语法规则:

1. SQL语句中字母不区分大小写,但是一般习惯关键字大写,库名、表名、字段名小写;
2. SQL语句都是用";"结尾的,尤其是在命令行中,不输入";",系统就会默认该条语句一直没有执行完;
3. SQL语句的语法符合英语的习惯,如创建数据库test的命令翻译过来就是:创建数据库test。

四,数据表增删改命令大全

讲完了数据库的命令,我们已经学会了怎么增、删、查数据库,并且成功地创建和使用自己的数据库。数据库是用来管理数据表的仓库,接下来需要学习数据表的命令。

在学习数据表的操作命令之前,有必要聊一下MySQL中的数据类型(了解即可):

数值类型

类型 大小 范围(有符号) 范围(无符号) 用途
TINYINT 1 byte (-128,127) (0,255) 小整数值
SMALLINT 2 bytes (-32 768,32 767) (0,65 535) 大整数值
MEDIUMINT 3 bytes (-8 388 608,8 388 607) (0,16 777 215) 大整数值
INT或INTEGER 4 bytes (-2 147 483 648,2 147 483 647) (0,4 294 967 295) 大整数值
BIGINT 8 bytes (-9,223,372,036,854,775,808,9 223 372 036 854 775 807) (0,18 446 744 073 709 551 615) 极大整数值
FLOAT 4 bytes (-3.402 823 466 E+38,-1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E+38) 0,(1.175 494 351 E-38,3.402 823 466 E+38) 单精度 浮点数值
DOUBLE 8 bytes (-1.797 693 134 862 315 7 E+308,-2.225 073 858 507 201 4 E-308),0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) 0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308) 双精度 浮点数值
DECIMAL 对DECIMAL(M,D) ,如果M>D,为M+2否则为D+2 依赖于M和D的值 依赖于M和D的值 小数值

日期和时间类型

类型 大小 ( bytes) 范围 格式 用途
DATE 3 1000-01-01/9999-12-31 YYYY-MM-DD 日期值
TIME 3 '-838:59:59'/'838:59:59' HH:MM:SS 时间值或持续时间
YEAR 1 1901/2155 YYYY 年份值
DATETIME 8 1000-01-01 00:00:00/9999-12-31 23:59:59 YYYY-MM-DD HH:MM:SS 混合日期和时间值
TIMESTAMP 4 1970-01-01 00:00:00/2038结束时间是第 2147483647 秒,北京时间 2038-1-19 11:14:07,格林尼治时间 2038年1月19日 凌晨 03:14:07 YYYYMMDD HHMMSS 混合日期和时间值,时间戳

字符串类型

类型 大小 用途
CHAR 0-255 bytes 定长字符串
VARCHAR 0-65535 bytes 变长字符串
TINYBLOB 0-255 bytes 不超过 255 个字符的二进制字符串
TINYTEXT 0-255 bytes 短文本字符串
BLOB 0-65 535 bytes 二进制形式的长文本数据
TEXT 0-65 535 bytes 长文本数据
MEDIUMBLOB 0-16 777 215 bytes 二进制形式的中等长度文本数据
MEDIUMTEXT 0-16 777 215 bytes 中等长度文本数据
LONGBLOB 0-4 294 967 295 bytes 二进制形式的极大文本数据
LONGTEXT 0-4 294 967 295 bytes 极大文本数据

1. 创建数据表

-- 创建学生表的命令
CREATE TABLE IF NOT EXISTS `student`(
  `id` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
  `stu_num` VARCHAR(5) NOT NULL COMMENT '学号',
  `name` VARCHAR(10) NOT NULL COMMENT '姓名',
  `age` TINYINT NOT NULL COMMENT '年龄',
  `birthday` DATE NULL COMMENT '生日'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT '学生表';

先分析创建表命令的主体部分,只需要将用汉字写出来的替换成实际表的内容即可:

CREATE TABLE [IF NOT EXISTS] 表名(...) ENGINE=InnoDB DEFAULT CHARSET=utf8 [COMMENT 备注];

再分析创建表命令中每个字段是怎么创建的:

字段名 字段类型1 [字段类型2 [字段类型3 ...]] [COMMENT 备注]

可以在navicat中选中表-右键-设计表查看创建的结果: avatar

双击表格则打开了一个只有字段名的空表:

avatar

2. 数据表的其它管理命令

数据表的其它管理命令可以参考库命令,直接上代码:

-- 查看当前数据库的表格
SHOW TABLES;

-- 查看某个表的创建语句
SHOW CREATE TABLE student;
-- CREATE TABLE `student` (
--   `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
--   `stu_num` varchar(5) NOT NULL COMMENT '学号',
--   `name` varchar(10) NOT NULL COMMENT '姓名',
--   `age` tinyint(4) NOT NULL COMMENT '年龄',
--   `birthday` date DEFAULT NULL COMMENT '生日',
--   PRIMARY KEY (`id`)
-- ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='学生表';

-- 查看表结构
DESC student;

-- 删除表
DROP TABLE student;

3. 向数据表中新增数据

有了数据表,就可以向数据表中添加数据了,MySQL中添加数据是按行(记录)添加,其命令如下:

-- 插入一条数据
INSERT INTO student VALUES(1, '20001', '小明', 20, '2000-01-01');

-- 按字段插入
INSERT INTO student(stu_num, `name`, age) VALUES('20002', '小芳', 18);

-- 插入多条数据
INSERT INTO student(stu_num, `name`, age, birthday)
VALUES('20003', '小磊', 21, '1999-05-23'),
    ('20004', '小赵', 19, '2001-08-18'),
('20005', '小王', 20, NULL);

由上面的代码可以总结插入数据的一般格式:

INSERT INTO 表名[字段1, 字段2,...字段n] 
VALUES(值1, 值2, ...值n),
    (值1, 值2, ...值n),
    (值1, 值2, ...值n);

需要注意的是,除了第一个命令中传入了id列的数据外,剩下的按字段插入数据的写法中均不需要传id。这是因为id列有自增属性,会根据已有的数值自动累加。但是无论怎样,表名后面所跟的字段数必须与VALUES后面所跟的字段数相同,且非空字段如果不传值则数据会添加失败。

下面的SQL语句均不能正确添加一条记录:

-- 表名后没有指定字段,而VALUES中又没有传id值
INSERT INTO student VALUES('20006', '小琳', 18, '2002-03-01');
-- > 1136 - Column count doesn't match value count at row 1

-- 表名后的字段数量与VALUES中的值数量不相等
INSERT INTO student(stu_num, `name`, age) VALUES('20006', '小琳', 18, '2002-03-01');
-- > 1136 - Column count doesn't match value count at row 1

-- 表名后的字段数量与VALUES中的值数量相等,但是部分非空字段未传值
INSERT INTO student(stu_num, age, birthday) VALUES('20006', 18, '2002-03-01');
-- > 1364 - Field 'name' doesn't have a default value

4. 删除数据表中的数据

上文提到的drop命令是删除整个数据表,如果想要删除部分数据,则可以使用delete命令,其中where条件是要删除数据的定位信息,如果没有定位,则默认清空整张表的数据,但是数据表依旧会保留:

-- 删除表数据
-- DELETE FROM 表名 [WHERE 条件];
-- 删除student表中姓名为小赵的同学信息
DELETE FROM student WHERE `name`='小赵';
-- 如果没有条件,则默认清空整张表
DELETE FROM student;

5. 修改数据表中的数据

与删除表中数据类似地,修改表中数据也要通过where条件定位,但是与删除表数据不同的是,如果不加where条件,则默认会修改每条记录的set后字段的值:

-- 更新表数据
-- UPDATE 表名 SET 字段1=字段1新值[, 字段2=字段2新值...] [WHERE 条件];
-- 将学号是2003的同学姓名修改为小强
UPDATE student SET `name` = '小强' WHERE stu_num = '2003';
-- 如果没有条件,则默认修改整个age字段的值
UPDATE student SET age = 18;

6. 修改数据表中的字段

操作数据表,有时候需要修改、添加和删除字段,其基本语法如下:

-- 基本语法
-- ALTER TABLE 表名 执行动作

-- 添加字段address
ALTER TABLE student ADD address VARCHAR(50) NULL;

-- 删除字段address
ALTER TABLE student DROP address;

-- 修改字段数据类型
ALTER TABLE student MODIFY stu_num INT;

-- 修改字段名和数据类型
ALTER TABLE student CHANGE stu_num stuNum INT(8);

-- 修改表名
ALTER TABLE student RENAME stu_info;

五,数据表的查询

1. MySQL运算符和聚合函数

不管什么应用场景,数据表的查询都是最难啃的一块骨头。为了能顺利地展示数据查询的代码,先来两碟开胃小菜,聊聊MySQL的运算符和聚合函数。

MySQL运算符

比较运算符:
数值比较:=, !=, <, <=, >, >=
字符比较:=, !=

逻辑运算符:AND, OR, NOT

空运算符:NULL, NOT NULL

范围:BETWEEN...AND..., IN, NOT IN

模糊比较:LIKE _(匹配单一字符)/%(匹配多字符)

正则匹配:regexp 正则表达式(^(以...开头), $(以...结尾), .(匹配单一字符), *(匹配多个字符), [](包含))

MySQL聚合函数

AVG(字段名):求字段平均值
SUM(字段名):求和
MAX(字段名):取最大值
MIN(字段名):取最小值
COUNT(字段名):计数

两点理解:
1,聚合函数通常与分组GROUP BY联合使用,全名为分组聚合,意为先分组再聚合,单独使用聚合函数不会输出结果;
2,求平均、求和、取最值的操作往往都是针对数值型字段,字符型的无法参与计算,但是计数适用于所有类型。

2. MySQL查询的完整语法

下面正式进入MySQL查询的命令。为了能从一开始对MySQL语法有一个整体的把握,我们从一开始就先抛出查询的完整语法,再逐项分解其功能和用法。

-- SQL查询的完整语法(展示用,不能执行)
SELECT *                  -- 这里写最后要显示的内容,可以是字段名,也可以是聚合函数,查询所有用*,
FROM stu_info [as] a      -- 这里写表名,可以用as关键字给表起别名,as可以省略
JOIN class [as] b         -- 这里是表连接的操作,使用join关键字连接两个表
ON a.stuNum = b.stuNum    -- 这里是连接表所依据的字段
WHERE a.age = 18          -- 这里是查询的条件
GROUP BY a.stuNum         -- 这里是分组的字段
HAVING COUNT(id) > 1      -- 这里是分组之后的筛选条件
ORDER BY a.stuNum DESC    -- 这里规定排序的规则,其中默认升序ASC,DESC是降序
LIMIT 5                   -- 这里是控制显示的数量
;                         -- 不管语句怎么变,最后的分号必须带上

3. 查询关键字SELECT

MySQL查询语句也被称为SELECT语句,先来了解一下SELECT的操作:

-- 最简单的MySQL查询语句
SELECT 1 + 1;
-- 猜猜会输出什么?

avatar

SELECT最基础的用法就是计算功能,四则运算通通不在话下。但是拿强大的SELECT去做算数运算好像还是大材小用了,下面我们去查询一下数据表吧!

-- 查询数据表的基本语法:
-- SELECT 字段名 FROM 表名;

-- 查询stu_info表中的所有内容
SELECT * FROM stu_info;

-- 查询stu_info表中stuNum和name字段的内容
SELECT stuNum, `name` FROM stu_info;

-- 使用AS给查询到的字段起个别名吧!AS也可以省略不写喔!
SELECT stuNum AS '学号', `name` AS '姓名' FROM stu_info;
SELECT stuNum '学号', `name` '姓名' FROM stu_info;

4. WHERE条件查询

之前的查询都会查出数据表的所有记录对应字段的信息,但是实际工作中,我们往往需要的是数据表中的部分数据,这时候通常会增加一个限制条件,如在某个时间段、数值大于多少等,因而引入了条件查询

-- 条件查询的基本语法:
-- SELECT 字段名 FROM 表名 WHERE 条件;

-- 查询年龄为20岁的学员信息
SELECT * FROM stu_info WHERE age = 20;

-- 查询在2000年以后出生的学员信息
SELECT * FROM stu_info WHERE birthday >= '2000-01-01';

-- 查询学号在20002和20004之间的学员信息
SELECT * FROM stu_info WHERE stuNum BETWEEN 20002 AND 20004;

-- 查询生日为空的学员信息
SELECT * FROM stu_info WHERE birthday IS NULL;

5. 对基础查询和条件查询的理解

1,单独基础查询会显示整个数据表的所有记录所查询字段的信息,相当于在EXCEL中折叠了其它列而单独显示某些列;
2,单独的条件查询会显示数据表中某些记录的完整信息,相当于EXCEL中折叠了其它行而单独显示某些行;
3,联合使用基础查询和条件查询,则可以实现相当于EXCEL中既折叠行又折叠列的操作,显示数据块。
-- 查询年龄为20岁的学员学号和姓名
SELECT stuNum '学号', `name` '姓名' FROM stu_info WHERE age = 20;

-- 查询在2000年以后出生的学员姓名
SELECT `name` FROM stu_info WHERE birthday >= '2000-01-01';

-- 查询学号在20002和20004之间的学员姓名和年龄
SELECT `name`, age FROM stu_info WHERE stuNum BETWEEN 20002 AND 20004;

-- 查询生日为空的学员姓名
SELECT `name` FROM stu_info WHERE birthday IS NULL;

6. GROUP BY分组

分组操作的是查询出来的数据,一般出现在基础查询或条件查询后。分组通常跟聚合函数同时出现,名为分组聚合,意为先分组,再聚合。其功能可以类比excel中的数据透视表。

-- 分组查询一般语法
-- SELECT 字段 FROM 表名 GROUP BY 字段;

-- 按照年龄进行分组,查询每个年龄的人数
SELECT age, COUNT(`age`) FROM stu_info GROUP BY age;

-- 按照出生的日期的月份分组,查询学生出生月份的分布
SELECT MONTH(birthday) mo, COUNT(`name`) FROM stu_info GROUP BY mo;

-- 查询年龄大于18岁的学员信息,并按照出生的日期的月份分组,查询学生出生月份的分布
SELECT MONTH(birthday) mo, COUNT(`name`) FROM stu_info WHERE age > 18 GROUP BY mo;

7. HAVING对分组后的数据做筛选

HAVING也是条件关键字,用于对分组之后的数据进行筛选,因此必须与GROUP BY联用。出于对SQL性能的要求,一般希望在分组之前做好数据筛选,以减少对无效数据的操作,因而使用HAVING的场景并不多。本案例由于数据量有限,以下举出的例子均可以使用WHERE实现,我会将两种实现语句都写出来,仅供参考。需要注意的是,当数据量较大时,两种查询语句的效率还是会有差别的,更推荐使用第二种。最后的最后,还是要强调一下废话了这么多的中心思想:能用WHERE的尽量不要用HAVING!

-- HAVING筛选一般语法
-- SELECT 字段 FROM 表名 GROUP BY 字段 HAVING 筛选条件;

-- 按照出生的日期的月份分组,查询学生出生月份的分布,排除掉没有生日信息的同学
-- 使用HAVING实现
SELECT MONTH(birthday) mo, COUNT(`name`) FROM stu_info GROUP BY mo HAVING mo IS NOT NULL;
-- 使用where实现:这里不能使用聚合字段mo,原因是where执行在分组聚合之前,参考SQL函数的执行顺序
SELECT MONTH(birthday) mo, COUNT(`name`) FROM stu_info WHERE birthday IS NOT NULL GROUP BY mo;

8. DISTINCT控制数据唯一性输出

当数据库中存在重复值时,直接查询会造成脏数据,此时需要使用DISTINCT去重。DISTINCT相当于EXCEL中的去除重复行的操作。

DISTINCT的另一个使用场景是对单个字段的去重,如使用COUNT(DISTINCT 字段)的嵌套实现在计数时先将字段数据去重的操作,通常用于分组聚合中对某些字段有重复值不计入的操作,如区域数量、销售经理数量的统计等。

为了演示DISTINCT的用法,这里生成另外一张选课表并添加一波数据,可以看出这个学校的老师有的只教授一门课程,有的教授多门课程。

-- 创建学生选课表
CREATE TABLE IF NOT EXISTS `course`(
`id` INT(8) UNSIGNED PRIMARY KEY NOT NULL AUTO_INCREMENT COMMENT '主键',
`course_num` INT(8) NOT NULL COMMENT '课程编号',
`course_name` VARCHAR(20) NOT NULL COMMENT '课程编号',
`teacher` VARCHAR(10) NOT NULL COMMENT '课程编号',
`stu_num` VARCHAR(5) NOT NULL COMMENT '选课学生学号'
)ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT '学生选课情况表';

-- 添加学生选课数据
INSERT INTO course(course_num, course_name, teacher, stu_num)
VALUES(10001, '统计数学', '胡六一', 20001),
(10001, '统计数学', '胡六一', 20002),
(10001, '统计数学', '王瘦子', 20003),
(10001, '统计数学', '王瘦子', 20004),
(10001, '统计数学', '小铁牙', 20005),
(10002, '计算机原理', '有正', 20001),
(10002, '计算机原理', '有正', 20002),
(10002, '计算机原理', '有正', 20003),
(10002, '计算机原理', '胡六一', 20005),
(10003, 'SQL从入门到放弃', '小铁牙', 20001),
(10003, 'SQL从入门到放弃', '小铁牙', 20003),
    (10003, 'SQL从入门到放弃', '小铁牙', 20004),
(10003, 'SQL从入门到放弃', '小铁牙', 20005);
-- 查询开始的课程
SELECT DISTINCT course_name from course;

-- 查看老师和所教课程的数量
-- 没有去重情况下筛选出来的是选择该老师的次数
SELECT teacher, COUNT(course_name) FROM course GROUP BY teacher;
-- 去重后筛选出来的才是老师教授的课程数量
SELECT teacher, COUNT(DISTINCT course_name) FROM course GROUP BY teacher;

-- 查看每门课的任课教师人数
SELECT course_name, COUNT(DISTINCT teacher) FROM course GROUP BY course_name;

9. ORDER BY排序

当需要对查询结果进行排序的时候,需要使用ORDER BY关键字,排序默认升序(ASC 可省略),当需要降序排列时,可以使用DESC关键字做说明。

ORDER BY排序通常在所有的查询、分组聚合和分组后的筛选完成之后,因而在SQL语句中出现的位置往往靠后,执行的顺序也靠后。

-- 排序的一般语法
-- SELECT 字段 FROM 表名 ORDER BY 字段 ASC/DESC;

-- 查询所有学员信息,按年龄从小打到大排序
SELECT * FROM stu_info ORDER BY age;

-- 查询所有学员的姓名和年龄,按年龄从大打到小排序
SELECT `name`, age FROM stu_info ORDER BY age DESC;

10. LIMIT限制查询数量

使用LIMIT可以限制查询的偏移和一次查询的记录个数,LIMIT永远出现在SQL语句的最后,执行顺序上也是最后才执行。

-- LIMIT基本语法
-- 这里的m是限制显示的数量,意义为显示前m条记录
-- SELECT 字段 FROM 表名 LIMIT m;
-- 这里的m是限制偏移,n限制显示的数量,意义为从第m+1条开始显示n条记录
-- SELECT 字段 FROM 表名 LIMIT m, n;

-- 查询所有学员信息,按年龄从小打到大排序,只显示前三条
SELECT * FROM stu_info ORDER BY age LIMIT 3;

-- 查询所有学员信息,按年龄从小打到大排序,显示2-4条
SELECT * FROM stu_info ORDER BY age LIMIT 1, 3;
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。