乐趣区

关于mysql:SQL教程

SQL 就是拜访和解决关系数据库的计算机规范语言。也就是说,无论用什么编程语言(Java、Python、C++……)编写程序,只有波及到操作关系数据库,比方,一个电商网站须要把用户和商品信息存入数据库,或者一个手机游戏须要把用户的道具、通关信息存入数据库,都必须通过 SQL 来实现。

NoSQL

你可能还据说过 NoSQL 数据库,也就是非 SQL 的数据库,包含 MongoDB、Cassandra、Dynamo 等等,它们都不是关系数据库。有很多人宣扬古代 Web 程序曾经无需关系数据库了,只须要应用 NoSQL 就能够。但事实上,SQL 数据库从始至终从未被取代过。

关系数据库概述

数据库作为一种专门治理数据的软件就呈现了。应用程序不须要本人治理数据,而是通过数据库软件提供的接口来读写数据。至于数据自身如何存储到文件,那是数据库软件的事件,应用程序本人并不关怀:

┌──────────────┐
│ application  │
└──────────────┘
       ▲│
       ││
   read││write
       ││
       │▼
┌──────────────┐
│   database   │
└──────────────┘

这样一来,编写应用程序的时候,数据读写的性能就被大大地简化了。

数据模型

数据库依照数据结构来组织、存储和治理数据,实际上,数据库一共有三种模型:

  • 层次模型
  • 网状模型
  • 关系模型

层次模型就是以“上下级”的档次关系来组织数据的一种形式,层次模型的数据结构看起来就像一颗树:

            ┌─────┐
            │     │
            └─────┘
               │
       ┌───────┴───────┐
       │               │
    ┌─────┐         ┌─────┐
    │     │         │     │
    └─────┘         └─────┘
       │               │
   ┌───┴───┐       ┌───┴───┐
   │       │       │       │
┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐
│     │ │     │ │     │ │     │
└─────┘ └─────┘ └─────┘ └─────┘

网状模型把每个数据节点和其余很多节点都连接起来,它的数据结构看起来就像很多城市之间的路网:

     ┌─────┐      ┌─────┐
   ┌─│     │──────│     │──┐
   │ └─────┘      └─────┘  │
   │    │            │     │
   │    └──────┬─────┘     │
   │           │           │
┌─────┐     ┌─────┐     ┌─────┐
│     │─────│     │─────│     │
└─────┘     └─────┘     └─────┘
   │           │           │
   │     ┌─────┴─────┐     │
   │     │           │     │
   │  ┌─────┐     ┌─────┐  │
   └──│     │─────│     │──┘
      └─────┘     └─────┘

关系模型把数据看作是一个二维表格,任何数据都能够通过行号 + 列号来惟一确定,它的数据模型看起来就是一个 Excel 表:

┌─────┬─────┬─────┬─────┬─────┐
│     │     │     │     │     │
├─────┼─────┼─────┼─────┼─────┤
│     │     │     │     │     │
├─────┼─────┼─────┼─────┼─────┤
│     │     │     │     │     │
├─────┼─────┼─────┼─────┼─────┤
│     │     │     │     │     │
└─────┴─────┴─────┴─────┴─────┘

随着工夫的推移和市场竞争,最终,基于关系模型的关系数据库取得了相对市场份额。

为什么关系数据库取得了最宽泛的利用?

因为相比层次模型和网状模型,关系模型了解和应用起来最简略。

基于数学实践的关系模型尽管讲起来挺简单,然而,基于日常生活的关系模型却非常容易了解。咱们以学校班级为例,一个班级的学生就能够用一个表格存起来,
其中,班级 ID 对应着另一个班级表

通过给定一个班级名称,能够查到一条班级记录,依据班级 ID,又能够查到多条学生记录,这样,二维表之间就通过 ID 映射建设了“一对多”关系。

数据类型

对于一个关系表,除了定义每一列的名称外,还须要定义每一列的数据类型。关系数据库反对的规范数据类型包含数值、字符串、工夫等

抉择数据类型的时候,要依据业务规定抉择适合的类型。通常来说,BIGINT能满足整数存储的需要,VARCHAR(N)能满足字符串存储的需要,这两种类型是应用最宽泛的。

SQL

什么是 SQL?SQL 是结构化查询语言的缩写,用来拜访和操作数据库系统。SQL 语句既能够查询数据库中的数据,也能够增加、更新和删除数据库中的数据,还能够对数据库进行治理和保护操作。不同的数据库,都反对 SQL,这样,咱们通过学习 SQL 这一种语言,就能够操作各种不同的数据库。

尽管 SQL 曾经被 ANSI 组织定义为规范,可怜地是,各个不同的数据库对规范的 SQL 反对不太统一。并且,大部分数据库都在规范的 SQL 上做了扩大。也就是说,如果只应用规范 SQL,实践上所有数据库都能够反对,但如果应用某个特定数据库的扩大 SQL,换一个数据库就不能执行了。例如,Oracle 把本人扩大的 SQL 称为PL/SQL,Microsoft 把本人扩大的 SQL 称为T-SQL

现实情况是,如果咱们只应用规范 SQL 的外围性能,那么所有数据库通常都能够执行。不罕用的 SQL 性能,不同的数据库反对的水平都不一样。而各个数据库反对的各自扩大的性能,通常咱们把它们称之为“方言”。

总的来说,SQL 语言定义了这么几种操作数据库的能力:

DDL:Data Definition Language

DDL 容许用户定义数据,也就是创立表、删除表、批改表构造这些操作。通常,DDL 由数据库管理员执行。

DML:Data Manipulation Language

DML 为用户提供增加、删除、更新数据的能力,这些是应用程序对数据库的日常操作。

DQL:Data Query Language

DQL 容许用户查问数据,这也是通常最频繁的数据库日常操作。

语法特点

SQL 语言关键字不辨别大小写!!!然而,针对不同的数据库,对于表名和列名,有的数据库辨别大小写,有的数据库不辨别大小写。同一个数据库,有的在 Linux 上辨别大小写,有的在 Windows 上不辨别大小写。

所以,本教程约定:SQL 关键字总是大写,以示突出,表名和列名均应用小写。

装置 MySQL

MySQL 是目前利用最宽泛的开源关系数据库。MySQL 最早是由瑞典的 MySQL AB 公司开发,该公司在 2008 年被 SUN 公司收买,紧接着,SUN 公司在 2009 年被 Oracle 公司收买,所以 MySQL 最终就变成了 Oracle 旗下的产品。

和其余关系数据库有所不同的是,MySQL 自身实际上只是一个 SQL 接口,它的外部还蕴含了多种数据引擎,罕用的包含:

  • InnoDB:由 Innobase Oy 公司开发的一款反对事务的数据库引擎,2006 年被 Oracle 收买;
  • MyISAM:MySQL 晚期集成的默认数据库引擎,不反对事务。

MySQL 接口和数据库引擎的关系就好比某某浏览器和浏览器引擎(IE 引擎或 Webkit 引擎)的关系。对用户而言,切换浏览器引擎不影响浏览器界面,切换 MySQL 引擎不影响本人写的应用程序应用 MySQL 的接口。

应用 MySQL 时,不同的表还能够应用不同的数据库引擎。如果你不晓得应该采纳哪种引擎,记住总是抉择_InnoDB_就好了。

装置 MySQL

要在 Windows 或 Mac 上装置 MySQL,首先从 MySQL 官方网站下载最新的 MySQL Community Server 版本:

https://dev.mysql.com/downloads/mysql/

抉择对应的操作系统版本,下载安装即可。在装置过程中,MySQL 会主动创立一个 root 用户,并提醒输出 root 口令。

要在 Linux 上装置 MySQL,能够应用发行版的包管理器。例如,Debian 和 Ubuntu 用户能够简略地通过命令 apt-get install mysql-server 装置最新的 MySQL 版本。

运行 MySQL

MySQL 装置后会主动在后盾运行。为了验证 MySQL 装置是否正确,咱们须要通过 mysql 这个命令行程序来连贯 MySQL 服务器。

在命令提示符下输出mysql -u root -p,而后输出口令,如果所有正确,就会连贯到 MySQL 服务器,同时提示符变为mysql>

输出 exit 退出 MySQL 命令行。留神,MySQL 服务器仍在后盾运行。

关系模型

咱们曾经晓得,关系数据库是建设在关系模型上的。而关系模型实质上就是若干个存储数据的二维表,能够把它们看作很多 Excel 表。

表的每一行称为记录(Record),记录是一个逻辑意义上的数据。

表的每一列称为字段(Column),同一个表的每一行记录都领有雷同的若干字段。

字段定义了数据类型(整型、浮点型、字符串、日期等),以及是否容许为 NULL。留神NULL 示意字段数据不存在。一个整型字段如果为 NULL 不示意它的值为 0,同样的,一个字符串型字段为NULL 也不示意它的值为空串''

通常状况下,字段应该防止容许为 NULL。不容许为 NULL 能够简化查问条件,放慢查问速度,也利于应用程序读取数据后无需判断是否为 NULL。

和 Excel 表有所不同的是,关系数据库的表和表之间须要建设“一对多”,“多对一”和“一对一”的关系,这样才可能依照应用程序的逻辑来组织和存储数据。
一个班级表, 每一行对应着一个班级,而一个班级对应着多个学生,所以班级表和学生表的关系就是“一对多”反过来,如果咱们先在学生表中定位了一行记录,例如 ID=1 的小明,要确定他的班级,只须要依据他的“班级 ID”对应的值 201 找到班级表中 ID=201 的记录,即二年级一班。所以,学生表和班级表是“多对一”的关系。班级表和老师表就是“一对一”关系。

在关系数据库中,关系是通过_主键_和_外键_来保护的。咱们在前面会别离深刻解说。

主键

每一条记录都蕴含若干定义好的字段。同一个表的所有记录都有雷同的字段定义。

对于关系表,有个很重要的束缚,就是任意两条记录不能反复。不能反复不是指两条记录不完全相同,而是指可能通过某个字段惟一辨别出不同的记录,这个字段被称为_主键_。

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

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

因为主键的作用非常重要,如何选取主键会对业务开发产生重要影响。如果咱们以学生的身份证号作为主键,仿佛能惟一定位记录。然而,身份证号也是一种业务场景,如果身份证号升位了,或者须要变更,作为主键,不得不批改的时候,就会对业务产生重大影响。

所以,选取主键的一个根本准则是:不应用任何业务相干的字段作为主键。

因而,身份证号、手机号、邮箱地址这些看上去能够惟一的字段,均_不可_用作主键。

作为主键最好是齐全业务无关的字段,咱们个别把这个字段命名为 id。常见的可作为id 字段的类型有:

  1. 自增整数类型:数据库会在插入数据时主动为每一条记录调配一个自增整数,这样咱们就齐全不必放心主键反复,也不必本人事后生成主键;
  2. 全局惟一 GUID 类型:应用一种全局惟一的字符串作为主键,相似8f55d96b-8acc-4636-8cb8-76bf8abc2f57。GUID 算法通过网卡 MAC 地址、工夫戳和随机数保障任意计算机在任意工夫生成的字符串都是不同的,大部分编程语言都内置了 GUID 算法,能够本人估算出主键。

对于大部分利用来说,通常自增类型的主键就能满足需要。咱们在 students 表中定义的主键也是 BIGINT NOT NULL AUTO_INCREMENT 类型

联结主键

关系数据库实际上还容许通过多个字段惟一标识记录,即两个或更多的字段都设置为主键,这种主键被称为联结主键。

对于联结主键,容许一列有反复,只有不是所有主键列都反复即可
没有必要的状况下,咱们尽量不应用联结主键,因为它给关系表带来了复杂度的回升。

外键

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

因为一个班级能够有多个学生,在关系模型中,这两个表的关系能够称为“一对多”,即一个 classes 的记录能够对应多个 students 表的记录。

为了表白这种一对多的关系,咱们须要在 students 表中退出一列 class_id,让它的值与classes 表的某条记录绝对应

这样,咱们就能够依据 class_id 这个列间接定位出一个 students 表的记录应该对应到 classes 的哪条记录。

例如:

  • 小明的 class_id1,因而,对应的 classes 表的记录是 id=1 的一班;
  • 小红的 class_id1,因而,对应的 classes 表的记录是 id=1 的一班;
  • 小白的 class_id2,因而,对应的 classes 表的记录是 id=2 的二班。

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

外键并不是通过列名实现的,而是通过定义外键束缚实现的:

ALTER TABLE students
ADD CONSTRAINT fk_class_id
FOREIGN KEY (class_id)
REFERENCES classes (id);

其中,外键束缚的名称 fk_class_id 能够任意,FOREIGN KEY (class_id)指定了 class_id 作为外键,REFERENCES classes (id)指定了这个外键将关联到 classes 表的 id 列(即 classes 表的主键)。

通过定义外键束缚,关系数据库能够保障无奈插入有效的数据。即如果 classes 表不存在 id=99 的记录,students表就无奈插入 class_id=99 的记录。

因为外键束缚会升高数据库的性能,大部分互联网应用程序为了谋求速度,并不设置外键束缚,而是仅靠应用程序本身来保障逻辑的正确性。这种状况下,class_id仅仅是一个一般的列,只是它起到了外键的作用而已。

要删除一个外键束缚,也是通过 ALTER TABLE 实现的:

ALTER TABLE students
DROP FOREIGN KEY fk_class_id;

留神:删除外键束缚并没有删除外键这一列。删除列是通过 DROP COLUMN ... 实现的。

多对多

通过一个表的外键关联到另一个表,咱们能够定义出一对多关系。有些时候,还须要定义“多对多”关系。例如,一个老师能够对应多个班级,一个班级也能够对应多个老师,因而,班级表和老师表存在多对多关系。

多对多关系实际上是通过两个一对多关系实现的,即通过一个两头表,关联两个一对多关系,就造成了多对多关系

通过两头表 teacher_class 可知 teachersclasses的关系:

  • id=1的张老师对应 id=1,2 的一班和二班;
  • id=2的王老师对应 id=1,2 的一班和二班;
  • id=3的李老师对应 id=1 的一班;
  • id=4的赵老师对应 id=2 的二班。

同理可知 classesteachers的关系:

  • id=1的一班对应 id=1,2,3 的张老师、王老师和李老师;
  • id=2的二班对应 id=1,2,4 的张老师、王老师和赵老师;

因而,通过两头表,咱们就定义了一个“多对多”关系。

一对一

一对一关系是指,一个表的记录对应到另一个表的惟一一个记录。

例如,students表的每个学生能够有本人的联系方式,如果把联系方式存入另一个表contacts,咱们就能够失去一个“一对一”关系

既然是一对一关系,那为啥不给 students 表减少一个 mobile 列,这样就能合二为一了?

如果业务容许,齐全能够把两个表合为一个表。然而,有些时候,如果某个学生没有手机号,那么,contacts表就不存在对应的记录。实际上,一对一关系精确地说,是 contacts 表一对一对应 students 表。

还有一些利用会把一个大表拆成两个一对一的表,目标是把常常读取和不常常读取的字段离开,以取得更高的性能。例如,把一个大的用户表分拆为用户根本信息表 user_info 和用户详细信息表 user_profiles,大部分时候,只须要查问user_info 表,并不需要查问 user_profiles 表,这样就进步了查问速度。

小结

关系数据库通过外键能够实现一对多、多对多和一对一的关系。外键既能够通过数据库来束缚,也能够不设置束缚,仅依附应用程序的逻辑来保障。

索引

在关系数据库中,如果有上万甚至上亿条记录,在查找记录的时候,想要取得十分快的速度,就须要应用索引。

索引是关系数据库中对某一列或多个列的值进行预排序的数据结构。通过应用索引,能够让数据库系统不用扫描整个表,而是间接定位到符合条件的记录,这样就大大放慢了查问速度。

如果要常常依据 score 列进行查问,就能够对 score 列创立索引:

ALTER TABLE students
ADD INDEX idx_score (score);

应用 ADD INDEX idx_score (score) 就创立了一个名称为 idx_score,应用列score 的索引。索引名称是任意的,索引如果有多列,能够在括号里顺次写上,例如:

ALTER TABLE students
ADD INDEX idx_name_score (name, score);

索引的效率取决于索引列的值是否散列,即该列的值如果越互不雷同,那么索引效率越高。反过来,如果记录的列存在大量雷同的值,例如 gender 列,大概一半的记录值是M,另一半是F,因而,对该列创立索引就没有意义。

能够对一张表创立多个索引。索引的长处是进步了查问效率,毛病是在插入、更新和删除记录时,须要同时批改索引,因而,索引越多,插入、更新和删除记录的速度就越慢。

对于主键,关系数据库会主动对其创立主键索引。应用主键索引的效率是最高的,因为主键会保障相对惟一。

惟一索引

在设计关系数据表的时候,看上去惟一的列,例如身份证号、邮箱地址等,因为他们具备业务含意,因而不宜作为主键。

然而,这些列依据业务要求,又具备唯一性束缚:即不能呈现两条记录存储了同一个身份证号。这个时候,就能够给该列增加一个惟一索引。例如,咱们假如 students 表的 name 不能反复:

ALTER TABLE students
ADD UNIQUE INDEX uni_name (name);

通过 UNIQUE 关键字咱们就增加了一个惟一索引。

也能够只对某一列增加一个惟一束缚而不创立惟一索引:

ALTER TABLE students
ADD CONSTRAINT uni_name UNIQUE (name);

这种状况下,name列没有索引,但依然具备唯一性保障。

无论是否创立索引,对于用户和应用程序来说,应用关系数据库不会有任何区别。这里的意思是说,当咱们在数据库中查问时,如果有相应的索引可用,数据库系统就会主动应用索引来进步查问效率,如果没有索引,查问也能失常执行,只是速度会变慢。因而,索引能够在应用数据库的过程中逐渐优化。

小结

通过对数据库表创立索引,能够进步查问速度。

通过创立惟一索引,能够保障某一列的值具备唯一性。

数据库索引对于用户和应用程序来说都是通明的。

查问数据

在关系数据库中,最罕用的操作就是查问。

根本查问

要查询数据库表的数据,咱们应用如下的 SQL 语句:

SELECT * FROM students;

SELECT是关键字,示意将要执行一个查问,*示意“所有列”,FROM示意将要从哪个表查问,本例中是 students 表。
该 SQL 将查问出 students 表的所有数据。留神:查问后果也是一个二维表,它蕴含列名和每一行的数据。

小结

应用 SELECT 查问的根本语句 SELECT * FROM < 表名 > 能够查问一个表的所有行和所有列的数据。

SELECT 查问的后果是一个二维表。

条件查问

应用 SELECT * FROM < 表名 > 能够查问到一张表的所有记录。然而,很多时候,咱们并不心愿取得所有记录,而是依据条件选择性地获取指定条件的记录,例如,查问分数在 80 分以上的学生记录。在一张表有数百万记录的状况下,获取所有记录不仅费时,还费内存和网络带宽。

SELECT 语句能够通过 WHERE 条件来设定查问条件,查问后果是满足查问条件的记录。例如,要指定条件“分数在 80 分或以上的学生”,写成 WHERE 条件就是:

SELECT * FROM students WHERE score >= 80

其中,WHERE关键字前面的 score >= 80 就是条件。score是列名,该列存储了学生的问题,因而,score >= 80就筛选出了指定条件的记录

因而,条件查问的语法就是:

SELECT * FROM < 表名 > WHERE < 条件表达式 >

条件表达式能够用 < 条件 1 > AND < 条件 2 > 表白满足条件 1 并且满足条件 2。例如,符合条件“分数在 80 分或以上”,并且还符合条件“男生”,把这两个条件写进去:

  • 条件 1:依据 score 列的数据判断:score >= 80
  • 条件 2:依据 gender 列的数据判断:gender = 'M',留神 gender 列存储的是字符串,须要用单引号括起来。

就能够写出 WHERE 条件:score >= 80 AND gender = 'M'

第二种条件是 < 条件 1 > OR < 条件 2 >,示意满足条件 1 或者满足条件 2。例如,把上述AND 查问的两个条件改为OR,查问后果就是“分数在 80 分或以上”或者“男生”,满足任意之一的条件即选出该记录:

SELECT * FROM students WHERE score >= 80 OR gender = 'M';

第三种条件是NOT < 条件 >,示意“不合乎该条件”的记录。例如,写一个“不是 2 班的学生”这个条件,能够先写出“是 2 班的学生”:class_id = 2,再加上NOTNOT class_id = 2

SELECT * FROM students WHERE NOT class_id = 2;

上述 NOT 条件 NOT class_id = 2 其实等价于 class_id <> 2,因而,NOT 查问不是很罕用。

要组合三个或者更多的条件,就须要用小括号 () 示意如何进行条件运算。例如,编写一个简单的条件:分数在 80 以下或者 90 以上,并且是男生:

SELECT * FROM students WHERE (score < 80 OR score > 90) AND gender = 'M';

如果不加括号,条件运算依照 NOTANDOR 的优先级进行,即 NOT 优先级最高,其次是AND,最初是OR。加上括号能够扭转优先级。

投影查问

应用 SELECT * FROM < 表名 > WHERE < 条件 > 能够选出表中的若干条记录。咱们留神到返回的二维表构造和原表是雷同的,即后果集的所有列与原表的所有列都一一对应。

如果咱们只心愿返回某些列的数据,而不是所有列的数据,咱们能够用SELECT 列 1, 列 2, 列 3 FROM ...,让后果集仅蕴含指定列。这种操作称为投影查问。

例如,从 students 表中返回 idscorename这三列:

SELECT id, score, name FROM students;

这样返回的后果集就只蕴含了咱们指定的列,并且,后果集的列的程序和原表能够不一样。

应用 SELECT 列 1, 列 2, 列 3 FROM ... 时,还能够给每一列起个别名,这样,后果集的列名就能够与原表的列名不同。它的语法是SELECT 列 1 别名 1, 列 2 别名 2, 列 3 别名 3 FROM ...

例如,以下 SELECT 语句将列名 score 重命名为 points,而idname列名放弃不变:

SELECT id, score points, name FROM students;

排序

排序

咱们应用 SELECT 查问时,仔细的读者可能留神到,查问后果集通常是依照 id 排序的,也就是依据主键排序。这也是大部分数据库的做法。如果咱们要依据其余条件排序怎么办?能够加上 ORDER BY 子句。例如依照问题从低到高进行排序:

SELECT id, name, gender, score FROM students ORDER BY score;

如果要反过来,依照问题从高到底排序,咱们能够加上 DESC 示意“倒序”:

SELECT id, name, gender, score FROM students ORDER BY score DESC;

如果 score 列有雷同的数据,要进一步排序,能够持续增加列名。例如,应用 ORDER BY score DESC, gender 示意先按 score 列倒序,如果有雷同分数的,再按 gender 列排序:

SELECT id, name, gender, score FROM students ORDER BY score DESC, gender;

默认的排序规定是 ASC:“升序”,即从小到大。ASC 能够省略,即 ORDER BY score ASCORDER BY score成果一样。

如果有 WHERE 子句,那么 ORDER BY 子句要放到 WHERE 子句前面。例如,查问一班的学生问题,并依照倒序排序:

SELECT id, name, gender, score
FROM students
WHERE class_id = 1
ORDER BY score DESC;

分页查问

分页

应用 SELECT 查问时,如果后果集数据量很大,比方几万行数据,放在一个页面显示的话数据量太大,不如分页显示,每次显示 100 条。

要实现分页性能,实际上就是从后果集中显示第 1~100 条记录作为第 1 页,显示第 101~200 条记录作为第 2 页,以此类推。

因而,分页实际上就是从后果集中“截取”出第 M~N 条记录。这个查问能够通过 LIMIT <M> OFFSET <N> 子句实现。咱们先把所有学生依照问题从高到低进行排序, 把后果集分页,每页 3 条记录。要获取第 1 页的记录,能够应用LIMIT 3 OFFSET 0

SELECT id, name, gender, score
FROM students
ORDER BY score DESC
LIMIT 3 OFFSET 0;

上述查问 LIMIT 3 OFFSET 0 示意,对后果集从 0 号记录开始,最多取 3 条。留神 SQL 记录集的索引从 0 开始。

如果要查问第 2 页,那么咱们只须要“跳过”头 3 条记录,也就是对后果集从 3 号记录开始查问,把 OFFSET 设定为 3。

可见,分页查问的关键在于,首先要确定每页须要显示的后果数量 pageSize(这里是 3),而后依据当前页的索引pageIndex(从 1 开始),确定LIMITOFFSET应该设定的值:

  • LIMIT总是设定为pageSize
  • OFFSET计算公式为pageSize * (pageIndex - 1)

这样就能正确查问出第 N 页的记录集。

OFFSET超过了查问的最大数量并不会报错,而是失去一个空的后果集。

留神

OFFSET是可选的,如果只写LIMIT 15,那么相当于LIMIT 15 OFFSET 0

在 MySQL 中,LIMIT 15 OFFSET 30还能够简写成LIMIT 30, 15

应用 LIMIT <M> OFFSET <N> 分页时,随着 N 越来越大,查问效率也会越来越低。

聚合查问

如果咱们要统计一张表的数据量,例如,想查问 students 表一共有多少条记录,难道必须用 SELECT * FROM students 查出来而后再数一数有多少行吗?

这个办法当然能够,然而比拟弱智。对于统计总数、平均数这类计算,SQL 提供了专门的聚合函数,应用聚合函数进行查问,就是聚合查问,它能够疾速取得后果。

依然以查问 students 表一共有多少条记录为例,咱们能够应用 SQL 内置的 COUNT() 函数查问:

SELECT COUNT(*) FROM students;

COUNT(*)示意查问所有列的行数,要留神聚合的计算结果尽管是一个数字,但查问的后果依然是一个二维表,只是这个二维表只有一行一列,并且列名是COUNT(*)

通常,应用聚合查问时,咱们应该给列名设置一个别名,便于处理结果:
SELECT COUNT(*) num FROM students;

COUNT(*)COUNT(id) 实际上是一样的成果。另外留神,聚合查问同样能够应用 WHERE 条件,因而咱们能够不便地统计出有多少男生、多少女生、多少 80 分以上的学生等:
SELECT COUNT(*) boys FROM students WHERE gender = ‘M’;

除了 COUNT() 函数外,SQL 还提供了如下聚合函数:…..

留神,MAX()MIN() 函数并不限于数值类型。如果是字符类型,MAX()MIN() 会返回排序最初和排序最前的字符。

要统计男生的均匀问题,咱们用上面的聚合查问:
SELECT AVG(score) average FROM students WHERE gender = ‘M’;

要特地留神:如果聚合查问的 WHERE 条件没有匹配到任何行,COUNT()会返回 0,而 SUM()AVG()MAX()MIN()会返回NULL

分组

如果咱们要统计一班的学生数量,咱们晓得,能够用 SELECT COUNT(*) num FROM students WHERE class_id = 1;。如果要持续统计二班、三班的学生数量,难道必须一直批改WHERE 条件来执行 SELECT 语句吗?

对于聚合查问,SQL 还提供了“分组聚合”的性能。咱们察看上面的聚合查问:
SELECT COUNT(*) num FROM students GROUP BY class_id;

执行这个查问,COUNT()的后果不再是一个,而是 3 个,这是因为,GROUP BY子句指定了按 class_id 分组,因而,执行该 SELECT 语句时,会把 class_id 雷同的列先分组,再别离计算,因而,失去了 3 行后果。

然而这 3 行后果别离是哪三个班级的,不难看进去,所以咱们能够把 class_id 列也放入后果集中:
SELECT class_id, COUNT(*) num FROM students GROUP BY class_id;

多表查问

SELECT 查问岂但能够从一张表查问数据,还能够从多张表同时查问数据。查问多张表的语法是:SELECT * FROM < 表 1 > < 表 2 >

例如,同时从 students 表和 classes 表的“乘积”,即查问数据,能够这么写:
SELECT * FROM students, classes;

这种一次查问两个表的数据,查问的后果也是一个二维表,它是 students 表和 classes 表的“乘积”,即 students 表的每一行与 classes 表的每一行都两两拼在一起返回。后果集的列数是 students 表和 classes 表的列数之和,行数是 students 表和 classes 表的行数之积。

这种多表查问又称笛卡尔查问,应用笛卡尔查问时要十分小心,因为后果集是指标表的行数乘积,对两个各自有 100 行记录的表进行笛卡尔查问将返回 1 万条记录,对两个各自有 1 万行记录的表进行笛卡尔查问将返回 1 亿条记录。

你可能还留神到了,上述查问的后果集有两列 id 和两列 name,两列id 是因为其中一列是 students 表的 id,而另一列是classes 表的 id,然而在后果集中,不好辨别。两列name 同理

要解决这个问题,咱们依然能够利用投影查问的“设置列的别名”来给两个表各自的 idname列起别名:

SELECT
    students.id sid,
    students.name,
    students.gender,
    students.score,
    classes.id cid,
    classes.name cname
FROM students, classes;

留神,多表查问时,要应用 表名. 列名 这样的形式来援用列和设置别名,这样就防止了后果集的列名反复问题。然而,用 表名. 列名 这种形式列举两个表的所有列切实是很麻烦,所以 SQL 还容许给表设置一个别名,让咱们在投影查问中援用起来略微简洁一点:

SELECT
    s.id sid,
    s.name,
    s.gender,
    s.score,
    c.id cid,
    c.name cname
FROM students s, classes c;

留神到 FROM 子句给表设置别名的语法是 FROM < 表名 1 > < 别名 1 >, < 表名 2 > < 别名 2 >。这样咱们用别名sc别离示意 students 表和 classes 表。

连贯查问

连贯查问是另一种类型的多表查问。连贯查问对多个表进行 JOIN 运算,简略地说,就是先确定一个主表作为后果集,而后,把其余表的行有选择性地“连贯”在主表后果集上。

例如,咱们想要选出 students 表的所有学生信息,能够用一条简略的 SELECT 语句实现:
SELECT s.id, s.name, s.class_id, s.gender, s.score FROM students s;

退出移动版