网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
数值类型
类型(有符号) | 大小 | 范围 | 描述 |
TINYINT | 1字节 | (-128 ~ 127) | 小整型,通常用于存储一些整型枚举值 |
INT | 4字节 | (-2,147,483,648 ~ 2,147,483,647) | 整型,使用频率较高 |
BIGINT | 8字节 | (-9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807) | 长整型,通常存储比较大的数值 |
FLOAT(n,d) | 4字节 | 与n和d的值有关 | 单精度浮点数(不精准表达) |
DOUBLE(n,d) | 8字节 | 与n和d的值有关 | 双精度浮点数(不精准表达) |
DECIMAL(p,d) | 与p和d 的值有关 | 与p和d的值有关 | 定点数(精准表达) |
日期类型
类型 | 示例 | 描述 |
DATE | 2019-05-01 | 日期 |
TIME | 12:23:34 | 时间 |
DATETIME | 2019-05-01 12:23:34 | 日期时间 |
字符串类型
类型 | 范围 | 描述 |
CHAR(n) | n <= 255 | 定长字符串 |
VARCHAR(n) | n <= 65535 | 变长字符串 |
TEXT | 0 - 65535字节 | 长文本数据 |
MEDIUMTEXT | 0 - 16,777,215字节 | 中等长度文本数据 |
上面只是罗列出了几种最常用的数据类型,如果大家接触到了其他不常用的类型,可以自己在网上搜索一下相关的信息。
1.4 主键
主键是一列或多列的组合,用于标识表中唯一的一条记录。所以,它天然的一个属性就是不重复性,也不允许为NULL值。通常我们会使用自增的整型值来作为主键,由数据库管理系统来维护,既能保证唯一性,又使用起来很方便。一个表的主键,通常也会作为其他表引用的对象,即后面要讲到的外键。
1.5 外键
外键通常用来建立两张表之间的关联关系,一个表的外键通常是与之关联的另一个表的主键。这样在进行关联查询时,就可以通过两个表外键和主键之间的关系,将两张表连接起来,形成一张中间表,将两张表的信息融合,产生更大的价值。
1.6 索引
如果你想快速找到一本书中,你感兴趣的部分,你就会去查找目录,目录可以帮你快速定位到你想看的内容在哪一页。对于数据库中的表来说,索引就相当于是表的目录。**其存在的主要目的就是为了加快查询速度。**当然,索引也还有一些其他用途,其设计原理也是非常巧妙,我们会在下一篇SQL进阶文章中,详细讲解这块内容。
1.7 表关系
在关系型数据库中,表和表之间的关系通常有三种,1对1、1对多、多对多。为方便描述,我们假定有两张表,分别为表A和表B。
-
1对1,是指表A和表B通过某字段关联后,表A中的一条记录最多对应表B中的一条记录,表B中的一条记录也最多对应表A中的一条记录。
-
1对多,是指表A和表B通过某字段关联后,表A中的一条记录可能对应表B中的多条记录,而表B中的一条记录最多对应表A中的一条记录。
-
多对多,是指表A和表B通过某字段关联后,表A中的一条记录可能对应表B中的多条记录,而表B中的一条记录可能对应表A中的多条记录。
1对1 和 1对多关系,通常使用外键引用对应表的主键就可以表达。而多对多关系,通常需要使用中间表来表达,中间表中记录了两张表的主键的对应关系。
1.8 视图
如果一条SQL的结果在日常查询中经常被用到,我们通常就会考虑使用视图将其存储起来,下次再使用时直接读取视图,就会执行视图对应的SQL语句,非常地简洁方便。所以,视图就是一张虚拟的表。不过,值得注意的是,视图存储的是SQL语句,而不是SQL执行后的结果,其结果是每次执行时动态生成的,可能每次读取都会有变化。
1.9 集合
集合在数学领域表示“(各种各样的)事物的总和”,在数据库领域表示记录的集合。具体来说,表、视图和查询的执行结果都是记录的集合。是集合,就可以进行集合运算,如求并集、交集、差集等。另外,查询的执行结果也是集合,那么就可以把查询的结果再当做一个表,继续基于这个表做分析。这个便是子查询的理论基础。在第4部分,我们会详细讲到子查询。
2 SQL查询的基本语法
SQL是结构化查询语言(Structural Query Language)的简称,是开发者与数据库管理系统对话的语言。SQL用关键字、表名、列名、操作符等组合而成的一条语句,用来描述操作的内容。SQL是有国际标准的,因此其通用性不言而喻。
2.1 关键字
SQL有很多关键字,每个关键字的含义和用法都不相同。本文只罗列出在数据分析工作中与查询分析相关的常用的基础关键字及其含义,其中有一些会在下面的段落中详细讲解,如下表格所示:
关键字 | 描述 |
SELECT | 后面跟用户想获取的列或计算公式 |
FROM | 后面跟要读取数据的表 |
LEFT/RIGHT/INNER JOIN | 后面跟要进行关联的表 |
ON | 后面跟关联条件 |
WHERE | 后面跟过滤条件,只有满足条件的行才会保留下来 |
GROUP BY | 后面跟用来分组的列或计算公式 |
HAVING | 后面跟分组后的过滤条件 |
ORDER BY | 后面跟用于排序的列或计算公式 |
LIMIT | 从结果中选取前N行,后面跟具体行数 |
DISTINCT | 对后面跟的列进行去重 |
COUNT | 对指定的一列或多列计数,会忽略掉NULL值 |
SUM | 对指定的列求和,会忽略掉NULL值 |
AVG | 对指定的列求平均值,会忽略掉NULL值 |
MIN | 求指定列的最小值 |
MAX | 求指定列的最大值 |
ASC/DESC | ASC表示升序排列,DESC表示降序排列,与ORDER BY配合使用 |
[NOT] IN | 多条件搜索 |
[NOT] LIKE | 模糊匹配 |
REGEXP | 正则匹配 |
AND/OR/NOT | 逻辑判断符 |
[NOT] BETWEEN AND | 区间限定 |
[NOT] EXISTS | 判断集合是否为空 |
IS [NOT] NULL | 判断是否为NULL值 |
UNION/UNION ALL | 求两个集合的并集,UNION会剔除结果集中的重复记录,UNION ALL则会保留重复记录 |
AS | 取别名或用于使用查询结果集创建表 |
* | 单独出现或出现在"."后面表示表中的所有列,出现在两个字段间表示乘法 |
2.2 书写规则
SQL的书写规则非常简单灵活,但是如果不注意,也是很容易犯错的,工作中常用的规则如下:
a. 关键字、表名和列名等大小写不敏感;
b. 使用全英文半角(关键字、空格、符号)来书写;
c. SQL语句以分号结尾;
d. SQL语句的单词及运算符之间需使用半角空格或换行符来进行分隔;
e. 函数名和括号是一个整体,中间不能有空格,空参数函数括号不能省略;
f. 数字常量直接书写,如 20 ;
g. 日期和字符串常量需要使用英文单引号包裹起来,如 ‘2002-10-01 12:23:21’,‘Lily’;
h. 注释的三种写法:单行注释(#,–)和多行注释(/* */)。单行注释推荐使用"–"。
2.3 简单查询
最简单的查询语句莫过于"SELECT * FROM A",其中A表示数据表名A,这条
SQL的含义是从表A中查询出所有列的所有数据。"*"代表表A中的所有列,是一种简写形式。我们就从这条最简单的SQL开始,逐渐添加关键字,最后变成一条复杂的SQL。
接下来我们要讲解的简单查询,都是针对单个表的查询。针对单表的查询虽然比较简单,但是却是复杂查询的基础。为了方便演示,我们先定义一个数据表student,用于存储学生的信息,表里的数据如下所示:
从左到右列的含义依次为学号、姓名、年龄、英语成绩、数学成绩、总成绩。
2.4 过滤
如果要对表中的数据进行过滤,只保留满足我们需求的数据,那就要用到WHERE关键字了。WHERE关键字后跟的是由逻辑运算符连接的一个或多个表达式,每个表达式的最终结果为TRUE或FALSE,只保留表达式结果为TRUE的行。
例如,我们要获取英文成绩不合格的学生姓名和学号,则对应的SQL为
SELECT sno, name
FROM student
WHERE eng_score < 60
运行结果如下:
sno | name |
22270202 | Lily |
22270203 | Tom |
2.5 运算符
运算符,顾名思义就是用于做运算的符号。常见的运算符有三种,比较运算符、算术运算符和逻辑运算符。
比较运算符 | 含义 |
= | 等值比较 |
> | 大于 |
< | 小于 |
>= | 大于或等于 |
<= | 小于或等于 |
<> | 不等于 |
不等于的判断,目前绝大部分的数据库管理系统厂商也都支持了"!=“运算符,与”<>"表达的含义相同。
算术运算符 | 含义 |
+ | 加法运算 |
- | 减法运算 |
* | 乘法运算 |
/ | 除法运算 |
算术运算符在书写时可以紧挨着字段名写,如eng_score-math_score,所以字段名和表名的命名中不能使用中划线(“-”),否则它会被误判为是在做减法运算的。
逻辑运算符 | 含义 |
AND | 与,并且 |
OR | 或,或者 |
NOT | 非,取反 |
当存在多种逻辑运算符时,为了避免歧义,需要使用括号来界定执行的先后顺序,使用括号组织的表达式,可读性也会更强。建议大家不要去记忆逻辑运算符的优先级,容易记混,而且写出的SQL可读性比较差,最好是使用括号,来厘清多个逻辑条件的关系,清晰易懂,可读性强,不容易出错。
了解了上面这些运算符,我们便可以通过组合各种运算符,书写出WHERE后面复杂的表达式,来满足我们的过滤需求了。
2.6 分组聚合
分组聚合是指,我们可以将表中的数据,根据某一列或多列进行分组,然后将其他列的值进行聚合计算,如计数、求和和求平均值等。用到的关键字是GROUP BY,对于分组后的计算结果,我们还可以使用HAVING进行过滤。
例如,从student表中,求出不同年龄的人数、英语总成绩和数学成绩的平均值,且过滤掉。对应的SQL为
SELECT age, COUNT(sno) AS student_num,
SUM(eng_score) AS sum_eng_score,`` AVG(math_score) AS avg_math_score``FROM student``GROUP BY age``HAVING avg_math_score >= 60
运行后结果如下所示:
age | student_num | sum_eng_score | avg_math_score |
10 | 2 | 138 | 70.5 |
12 | 1 | 89 | 82 |
这里需要注意的是,出现在group by后面的字段或计算公式,必须出现在对应的select的后面,并且除了这些字段或计算公式外,select后面不能有其他字段,只能使用聚合函数。
2.7 去重
DISTINCT关键字用于对一列或多列去重,返回剔除了重复行的结果。DISTINCT对多列去重时,必须满足每一列都相同时,才认为是重复的行进行剔除。DISTINCT不会过滤掉NULL值,但去重后的结果只会保留一个NULL值。
例如,从student表中,找出有几种年龄的学生,即求出去重后的年龄。对应的SQL为
SELECT DISTINCT age FROM student
运行后的结果如下所示:
age |
10 |
11 |
12 |
2.8 排序
日常生活场景里,我们经常对各种各样的排名比较感兴趣,比较关注排在前面的内容。在数据库中,求出排名,就需要用到ORDER BY子句。ORDER BY通常配合ASC和DESC使用,可以根据一列或多列,进行升序或降序排列,之后使用LIMIT取出满足条件的前N行。
例如,从student表中,求出数学成绩最好的前3名学生的姓名、年龄和其数学成绩。对应的SQL如下:
SELECT name, age, math_scoreFROM student
ORDER BY math_score DESC``LIMIT 3
运行后的结果为:
name | age | math_score |
Jack | 12 | 82 |
Alice | 10 | 76 |
Tom | 10 | 65 |
2.9 增加常量列
增加常量列,即把某一固定的常量值做为一列添加到我们的结果数据中。这种做法的应用场景,通常是结果集中所有的行在某个属性上值是相同的,这时便可以通过增加常量列的方式,来增加这一列。我们通过下面的例子来演示其语法形式。
例如,从student表中,查询英语成绩大于80分的学生的姓名和学号,并把他们都分入A班。对应的SQL如下:
SELECT sno, name, ‘A’ AS class FROM student WHERE eng_score > 80
运行后的结果为:
sno | name | class |
22270201 | Alice | A |
22270204 | Jack | A |
从示例中可以看出,直接通过"常量 AS 新列名"的方式就可以增加常量列,非常地方便。
3 数据库函数、谓词和CASE表达式
SQL之所以具有强大的分析表达能力,其中一个重要原因,就是它具备丰富的函数,通过这些函数的组合可以实现对数据的复杂处理,最终得到我们想要的数据。另外一方面,SQL也有丰富的谓词来对数据进行判断,匹配出符合我们需求的数据。CASE表达式是一种多条件判断表达式,可以根据不同条件返回不同的值,类似于编程语言中的IF ELSE。
3.1 聚合函数
聚合函数,又称分析函数,是将一组值通过聚合分析后得到一个值,因此得名聚合函数。使用频率最高的聚合函数有5个,如下表所示
函数名 | 含义 |
COUNT | 计数 |
SUM | 求和 |
AVG | 求平均值 |
MIN | 求最小值 |
MAX | 求最大值 |
聚合函数有一个共同的特点,即在计算过程中都会忽略掉NULL值,因为对NULL的聚合是没有任何意义的。COUNT、SUM和AVG三个函数还可以和DISTINCT配合使用,其含义为先对目标列进行去重,之后再对去重后的结果聚合。SUM和AVG只能应用于一列,且列的数据类型为数值型。MIN和MAX也是只能应用于一列,不过除了支持数值型外,还支持字符串类型和日期类型。COUNT可以应用于一列或多列,而且不限制列的类型。
3.2 算术函数
算术函数,主要用于对数值类型进行各种数学运算。SQL中除了加减乘除(±*/)四个运算符外,还提供了一系列的算术函数,如下表所示:
函数名 | 含义 |
CEIL(x) | 向上取整 |
FLOOR(x) | 向下取整 |
ABS(x) | 求绝对值 |
ROUND(x, d) | 四舍五入,对x保留d位小数 |
POWER(x, y) | 幂运算,求x的y次方 |
MOD(x, y) | 取余数,求x被y整除后的余数 |
RAND([n]) | 返回0-1.0的随机数,n为随机种子,可以省略不写 |
这里只罗列了常用的一些函数,通过他们之间的组合,可以实现复杂的运算,如果上述表格不满足你的分析需求,可以自行Google或查看官方文档,寻找匹配的算术函数。
3.3 日期函数
日常分析工作中,经常需要对日期进行加减、格式化等处理,这就离不开强大的日期处理函数,常用的日期函数如下:
函数名 | 含义 |
CURDATE() | 返回当前日期 |
CURRENT_DATE() | 返回当前日期,和上面的函数作用相同 |
CURRENT_TIME() | 返回当前时间 |
NOW() | 返回当前的日期和时间 |
DATE_ADD(d, interval n unit) | 返回日期d加上n个单位后的时间,unit为具体单位,如day,表示天 |
DATE_SUB(d, interval n unit) | 返回日期d减去n个单位后的时间,unit为具体单位,如day,表示天 |
DATE_DIFF(d1, d2) | 返回日期d1和日期d2的天数差 |
DATE_FORMAT(d, 'format_exp') | 返回使用日期格式表达式format_exp格式化日期d后得到的字符串 |
YEAR(d) | 返回日期d的年份 |
MONTH(d) | 返回日期d的月份 |
DATE(d) | 返回日期时间d的日期部分,舍弃时间部分 |
日期函数用于获取当前日期时间的函数多数是空参数函数,虽然参数为空,但是函数名后的括号不能省略不写。数据库厂商虽然也提供了部分与函数名相同的属性值,不带括号也能调用,不过笔者建议最好还是使用函数带上空括号,这样识别度更高,可读性更好。
3.4 字符串函数
字符串是信息的一个重要载体,其中包含着大量的重要信息,因此对字符串的处理非常重要,相应地字符串处理函数也是非常丰富,以下我们罗列出最常用的一些函数:
函数 | 含义 | 使用示例 | 返回值 |
LENGTH(str) | 求字符串str的长度 | LENGTH('bigdata') | 7 |
INSTR(str, substr) | 返回substr在str第一次出现的位置(str不包含substr时返回0) | INSTR('bigdata', 'data') | 4 |
LEFT(str, len) | 返回str的左端len个字符 | LEFT('bigdata',3) | 'big' |
RIGHT(str, len) | 返回str的右端len个字符 | RIGHT('bigdata',4) | 'data' |
SUBSTRING(str, pos, len) | 返回str的从位置pos起len个字符 | SUBSTRING('bigdata',4,4) | 'data' |
SUBSTRING_INDEX(str, delim, count) | 当count为正数时,从左找到第count个分隔符delim所在位置,并返回其左侧的字符;否则从右开始找,并返回对应位置右侧的字符 | SUBSTRING_INDEX('180.97.33.108', '.', 3) | '180.97.33' |
REPLACE(str, from_str, to_str) | 返回用to_str替换str中的from_str后的字符串 | REPLACE('bigdata', 'big', 'Big') | 'Bigdata' |
LOWER(str) | 返回str转小写后的字符串 | LOWER('Bigdata') | 'bigdata' |
UPPER(str) | 返回str转大写后的字符串 | UPPER('Bigdata') | 'BIGDATA' |
CONCAT(str1, str2,...) | 将参数连接起来并返回 | CONCAT('big', 'data') | 'bigdata' |
CONCAT_WS(delim, str1, str2,...) | 将参数使用分隔符delim连接起来并返回 | CONCAT_WS('_', 'big', 'data') | 'big_data' |
3.5 转换函数
当某些数据的类型与我们需要的类型不符时,可以使用类型转换函数,将其类型转换为我们需要的类型。常用的类型转换函数有两个,分别为CAST和CONVERT,两个函数的作用是相同的,只是语法略有不同。CAST函数的用法为CAST(字段 AS 数据类型),而CONVERT的用法为CONVERT(字段, 数据类型)。
不过,并不是所有的类型都是可以互相转换的,而且有些转换会导致精度的损失,因此请谨慎使用。
3.6 其他函数
还有一些函数是使用在特定用途上的,本文也罗列出几个数据分析工作中常用的。
MD5函数,其作用是生成等长的信息摘要。在数据分析工作中,经常用于对敏感信息的脱敏,因为很难通过md5值反向推断加密前的内容,因此是非常安全的。其使用方法为,MD5(str),返回对str进行md5算法计算得到的校验和字符串。
IFNULL(expr1, expr2):如果expr1不为NULL,则返回expr1,否则返回expr2。通常用于对某个字段的NULL值填补,也叫缺失值填补。
IF(expr1, expr2, expr3):如果expr1不等于0或者不为NULL,则返回expr2的值,否则返回expr3的值。相当于编程语言中的IF ELSE条件判断语句
3.7 谓词
简单来说,谓词就是用于真假判断的关键字,用来判定两个对象间关系论断的真假,返回值只有真或假。这么说可能还是有点抽象。我们来举一些谓词的例子大家就明白了。
例如,我们前面讲到的比较运算符,就都属于谓词的范畴。还有一些其他谓词如下表所示:
谓词 | 含义 |
[NOT] LIKE | 模糊匹配,通常配合%和_使用 |
[NOT] IN | 多值包含关系判断 |
[NOT] BETWEEN ... AND ... | 区间判断 |
IS [NOT] NULL | 是否为NULL值判断 |
[NOT] EXISTS | 是否为空集合判断 |
[NOT] REGEXP | 是否满足正则表达式判断 |
3.8 CASE表达式
SQL语句中的CASE表达式,对应着编程语言中的条件分支,起到多条件判断返回多种值的作用。其语法形式为:
CASE
WHEN <求值表达式1> THEN <表达式1>
WHEN <求值表达式2> THEN <表达式2>
WHEN <求值表达式3> THEN <表达式3>
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
3.8 CASE表达式**
SQL语句中的CASE表达式,对应着编程语言中的条件分支,起到多条件判断返回多种值的作用。其语法形式为:
CASE
WHEN <求值表达式1> THEN <表达式1>
WHEN <求值表达式2> THEN <表达式2>
WHEN <求值表达式3> THEN <表达式3>
[外链图片转存中…(img-tlmu9lDZ-1715608129303)]
[外链图片转存中…(img-u4PxRnoc-1715608129304)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!