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 studentsADD CONSTRAINT fk_class_idFOREIGN 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 studentsDROP 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 studentsADD INDEX idx_score (score);

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

ALTER TABLE studentsADD INDEX idx_name_score (name, score);

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

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

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

惟一索引

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

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

ALTER TABLE studentsADD UNIQUE INDEX uni_name (name);

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

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

ALTER TABLE studentsADD 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, scoreFROM studentsWHERE class_id = 1ORDER 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, scoreFROM studentsORDER BY score DESCLIMIT 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 cnameFROM students, classes;

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

SELECT    s.id sid,    s.name,    s.gender,    s.score,    c.id cid,    c.name cnameFROM 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;