🔎什么是SQL
SQL就是访问和处理关系数据库的计算机标准语言。也就是说,无论用什么编程语言(Java、Python、C++……)编写程序,只要涉及到操作关系数据库,比如,一个电商网站需要把用户和商品信息存入数据库,或者一个手机游戏需要把用户的道具、通关信息存入数据库,都必须通过SQL来完成。所以,现代程序离不开关系数据库,要使用关系数据库就必须掌握SQL。
SQL的全称是Structured Query Language,即结构化查询语言。SQL语句既可以查询数据库中的数据,也可以添加、更新和删除数据库中的数据,还可以对数据库进行管理和维护操作。
SQL语言定义了以下几种操作数据库的能力:
DDL:Data Definition Language
DDL允许用户定义数据,也就是创建表、删除表、修改表结构这些操作。通常,DDL由数据库管理员执行。
DML:Data Manipulation Language
DML为用户提供添加、删除、更新数据的能力,这些是应用程序对数据库的日常操作。
DQL:Data Query Language
DQL允许用户查询数据,这也是通常最频繁的数据库日常操作。
为什么需要数据库?
因为应用程序需要保存用户的数据,比如Word需要把用户文档保存起来,以便下次继续编辑或者拷贝到另一台电脑。
要保存用户的数据,一个最简单的方法是把用户数据写入文件。例如,要保存一个班级所有学生的信息,可以向文件中写入一个CSV文件:
id,name,gender,score
1,小明,M,90
2,小红,F,95
3,小军,M,88
4,小丽,F,88
如果要保存学校所有班级的信息,可以写入另一个CSV文件。
但是,随着应用程序的功能越来越复杂,数据量越来越大,如何管理这些数据就成了大问题:
读写文件并解析出数据需要大量重复代码;
从成千上万的数据中快速查询出指定数据需要复杂的逻辑。
如果每个应用程序都各自写自己的读写数据的代码,一方面效率低,容易出错,另一方面,每个应用程序访问数据的接口都不相同,数据难以复用。
所以,数据库作为一种专门管理数据的软件就出现了。应用程序不需要自己管理数据,而是通过数据库软件提供的接口来读写数据。至于数据本身如何存储到文件,那是数据库软件的事情,应用程序自己并不关心:
这样一来,编写应用程序的时候,数据读写的功能就被大大地简化了。
数据库的结构模型
数据库按照数据结构来组织、存储和管理数据,实际上,数据库一共有三种模型:
层次模型:以“上下级”的层次关系来组织数据的一种方式,层次模型的数据结构看起来就像一颗树
网状模型:把每个数据节点和其他很多节点都连接起来,它的数据结构看起来就像很多城市之间的路网
关系模型:把数据看作是一个二维表格,任何数据都可以通过行号+列号来唯一确定,它的数据模型看起来就是一个Excel表
🔎关系数据库
随着时间的推移和市场竞争,最终,基于关系模型的关系数据库获得了绝对市场份额。相比层次模型和网状模型,关系模型理解和使用起来最简单。关系模型本质上就是若干个存储数据的二维表,可以把它们看作很多Excel表。和Excel表有所不同的是,关系数据库的表和表之间需要建立“一对多”,“多对一”和“一对一”的关系,这样才能够按照应用程序的逻辑来组织和存储数据。
表的每一行称为记录(Record),记录是一个逻辑意义上的数据。
表的每一列称为字段(Column),同一个表的每一行记录都拥有相同的若干字段。字段定义了数据类型(整型、浮点型、字符串、日期等),以及是否允许为NULL。注意NULL表示字段数据不存在。一个整型字段如果为NULL不表示它的值为0,同样的,一个字符串型字段为NULL也不表示它的值为空串''。
在关系数据库中,关系是通过主键和外键来维护的。
⭕主键
在关系数据库中,一张表中的每一行数据被称为一条记录。每一条记录都包含若干定义好的字段。同一个表的所有记录都有相同的字段定义。对于关系表,有个很重要的约束,就是任意两条记录不能重复。不能重复不是指两条记录不完全相同,而是指能够通过某个字段唯一区分出不同的记录,这个字段被称为主键。
例如,假设我们把name字段作为主键,那么通过名字小明或小红就能唯一确定一条记录。但是,这么设定,就没法存储同名的同学了,因为插入相同主键的两条记录是不被允许的。
对主键的要求,最关键的一点是:记录一旦插入到表中,主键最好不要再修改,因为主键是用来唯一定位记录的,修改了主键,会造成一系列的影响。选取主键的一个基本原则是:不使用任何业务相关的字段作为主键。
因此,身份证号、手机号、邮箱地址这些看上去可以唯一的字段,均不可用作主键。作为主键最好是完全业务无关的字段,我们一般把这个字段命名为id。
关系数据库实际上还允许通过多个字段唯一标识记录,即两个或更多的字段都设置为主键,这种主键被称为联合主键。对于联合主键,允许一列有重复,只要不是所有主键列都重复即可。
⭕外键
外键用来和其他表建立联系,表的外键是另一表的主键,外键是可以有重复的,可以是空值。
⭕索引
在关系数据库中,如果有上万甚至上亿条记录,在查找记录的时候,想要获得非常快的速度,就需要使用索引。
索引是关系数据库中对某一列或多个列的值进行预排序的数据结构。通过使用索引,可以让数据库系统不必扫描整个表,而是直接定位到符合条件的记录,这样就大大加快了查询速度。
索引的效率取决于索引列的值是否散列,即该列的值如果越互不相同,那么索引效率越高。反过来,如果记录的列存在大量相同的值,例如gender列,大约一半的记录值是M,另一半是F,因此,对该列创建索引就没有意义。
可以对一张表创建多个索引。索引的优点是提高了查询效率,缺点是在插入、更新和删除记录时,需要同时修改索引,因此,索引越多,插入、更新和删除记录的速度就越慢。
对于主键,关系数据库会自动对其创建主键索引。使用主键索引的效率是最高的,因为主键会保证绝对唯一。
查询数据库的基本语句
1. 指定查询
要查询数据库表所有行和所有列的数据,我们使用如下的SQL语句:
SELECT * FROM<表名>;
SELECT是关键字,表示将要执行一个查询,*表示“所有列”,FROM表示将要从哪个表查询,本例中是students表。SELECT查询的结果是一个二维表。
2. 条件查询
使用SELECT * FROM <表名>可以查询到一张表的所有记录。但是,很多时候,我们并不希望获得所有记录,而是根据条件选择性地获取指定条件的记录,例如,查询分数在80分以上的学生记录。在一张表有数百万记录的情况下,获取所有记录不仅费时,还费内存和网络带宽。
SELECT语句可以通过WHERE条件来设定查询条件,查询结果是满足查询条件的记录。例如,要指定条件“分数在80分或以上的学生”,写成WHERE条件就是:
SELECT * FROM students WHERE score >= 80;
条件表达式可以用<条件1> AND <条件2>表达满足条件1并且满足条件2。例如,符合条件“分数在80分或以上”,并且还符合条件“男生”,把这两个条件写出来:
SELECT * FROM students WHERE score >= 80 AND gender = 'M';
第I二种条件是<条件1> OR <条件2>,表示满足条件1或者满足条件2。例如,把上述AND查询的两个条件改为OR,查询结果就是“分数在80分或以上”或者“男生”,满足任意之一的条件即选出该记录:
SELECT * FROM students WHERE score >= 80 OR gender = 'M';
很显然OR条件要比AND条件宽松,返回的符合条件的记录也更多。
第三种条件是NOT <条件>,表示“不符合该条件”的记录。例如,写一个“不是2班的学生”这个条件,可以先写出“是2班的学生”:class_id = 2,再加上NOT:NOT class_id = 2:
SELECT * FROM students WHERE NOT class_id = 2;
要组合三个或者更多的条件,就需要用小括号()表示如何进行条件运算。例如,编写一个复杂的条件:分数在80以下或者90以上,并且是男生:
SELECT * FROM students WHERE (score <80 OR score>90) AND gender = 'M';
如果不加括号,条件运算按照NOT、AND、OR的优先级进行,即NOT优先级最高,其次是AND,最后是OR。加上括号可以改变优先级。
通过WHERE条件查询,可以筛选出符合指定条件的记录,而不是整个表的所有记录。
3. 投影查询
如果我们只希望返回某些列的数据,而不是所有列的数据,我们可以用SELECT 列1, 列2, 列3 FROM ...,让结果集仅包含指定列。这种操作称为投影查询。
例如,从students表中返回id、score和name这三列:
SELECT id, score, name FROM students;
4.排序
我们使用SELECT查询时,查询结果集通常是按照id排序的,也就是根据主键排序。这也是大部分数据库的做法。如果我们要根据其他条件排序怎么办?可以加上ORDER BY子句。例如按照成绩从低到高进行排序:
SELECT id, score, name FROM students ORDER BY score;
如果要反过来,按照成绩从高到底排序,我们可以加上DESC表示“倒序”:
SELECT id, score, name FROM students ORDER BY score DESC;
SELECT查询不但可以从一张表查询数据,还可以从多张表同时查询数据。查询多张表的语法是:SELECT * FROM <表1> <表2>。
5. 连接查询
内连接(INNER JOIN)
外连接(OUTER JOIN)
左连接(LEFT OUTER JOIN)
右连接(RIGHT OUTER JOIN)
全连接(FULL OUTER JOIN)
参考资料