标签:
关系型数据库管理系统简介
为什么使用数据库
1.降低存储数据的冗余度
2.更高的数据一致性
3.存储的数据可以共享
4.可以建立数据库所遵循的标准
5.便于维护数据完整性
6.能够实现数据的安全性
数据在数据库中的存储形式
1.层次模型(最早出现的模型)
2.网状模型
3.关系模型(最常用的模型)
4.对象模型
关系型数据库的基本概念
关系型数据库 = 实体 + 关系
表是关系型数据库的核心单元,它是数据存储的地方。 对任何关系型数据库来说,表之间的关联关系存在三种基本的关系类型:一对一关系、一对多关系、多对多关系。
1.一对一关系
有两个表,在第一个表中的一行只与第二个表中的一行相关,同时第二个表中的一行也只与第一个表中的一行相关时,我们称两个表之间是一对一关系。
2.一对多关系
有两个表,第一个表中的行可以与第二个表中的一到多个行相关联,但是第二个表中的一行只能与第一个表中的一行相关联.
3.多对多关系
有两个表,第一个表的一行可以与第二个表中的一到多个行相关联,同时,第二个表中的一行可以与第一个表中的一到多个行相关联。
关系型数据库管理系统
关系型数据库管理系统(RDBMS):管理关系型数据库的软件。
1.本地数据库管理系统
2.数据库服务器管理系统
结构化查询语言SQL
概念:SQL是一种用于管理关系型数据库,并与数据库中的数据进行通讯的计算机语言。
SQL语句分为:数据定义语言(DDL)、数据查询语言(DQL)、数据操作语言(DML)、数据控制语言(DCL)。
管理数据库和表
管理数据库
创建和使用数据库
在大多数RDBMS中,我们都可以使用如下简单的SQL语句,创建整个数据库:
CREATE DATABASE 数据库名;
其中,数据库名在服务器中必须是唯一的,并且符合标识符规则。所谓标识符规则指:
第一个字符必须是下列字符之一:
Unicode 标准 3.0 所定义的字母(Unicode 中定义的字母包括拉丁字母 a-z 和 A-Z,以及来自其它语言的字母字符)。
下划线 (_)、at 符号 (@) 或者数字符号 (#)。
后续字符可以是:
Unicode 标准 3.0 所定义的字母。
来自基本拉丁字母或其它国家/地区脚本的十进制数字。
at符号(@)、美元符号 ($)、数字符号或下划线。
标识符不能是所用RDBMS的保留字。
不允许嵌入空格或其它特殊字符。
连接到数据库
新的数据库创建完毕后,为了在该数据库上执行SQL语句,我们需要连接到该数据库上。连接到数据库用下面的语句:
USE 数据库名;
在MySQL中,默认情况下,所有数据库均为不活动状态。使用上面的命令,可以激活并使用某个数据库。其后,我们就可以针对该数据库执行SQL语句了。
删除数据库
删除数据库的方法为:
DROP DATABASE 数据库名;
数据类型
整数数据类型
类型 大小 范围(有符号) 范围(无符号) 用途
TINYINT 1字节 (-128,127) (0,255) 极小整数值
SMALLINT 2字节 (-32 768,32 767) (0,65 535) 小整数值
MEDIUMINT 3字节 (-8 388 608,
8 388 607) (0,16 777 215) 小整数值
INT 4字节 (-2 147 483 648,
2 147 483 647) (0,4 294 967 295) 整数值
BIGINT 8字节 (-9 233 372 036 854 775 808,
9 223 372 036 854 775 807) (0,18 446 744 073 709 551 615) 大整数值
浮点数据类型
类型 大小 范围 精度 用途
FLOAT 4字节 (-3.40E-38,3.40E+38) 7位小数 单精度浮点数
DOUBLE 8字节 (-8 388 608,
8 388 607) 15位小数 双精度浮点数
DECIMAL(M,D) 17字节 (-10的38次方-1 ,
10的38次方-1) 30位小数 大浮点数
NUMERIC(M,D) 同DECIMAL
注意: M为总位数,D为小数位,M必须大于D
字符串数据类型
类型 大小 范围 用途
CHAR(N) N 0-255 字符型
VARCHAR(N) N 0-65535 字符型
二进制数据类型
类型 大小 范围 用途
TINYBLOB 255 0-255 二进制大对象
BLOB 65K 0-65KB 二进制大对象
MEDIUMBLOB 16M 0-16M 二进制大对象
LONGBLOB 4G 0-4G 二进制大对象
逻辑数据类型
类型 范围 用途
BOOLEAN 0-1 MYSQL没有BOOLEAN类型,但BOOLEAN类型可以创建,在MYSQL中BOOLEAN别自动定义为TINYINT(1)
日期数据类型
类型 大小 格式 范围
YEAR 1字节 YYYY 1901 - 2155
DATE 3字节 YYYY-MM-DD 1000-01-01 - 9999-12-31
TIMESAMP 4字节 YYYY-MM-DD HH:MM:SS 1970-01-01 00:00:01 - 2038
DATATIME 8字节 YYYY-MM-DD HH:MM:SS 1000-01-01 00:00:00 - 9999-12-31 23:59:59
管理表
创建表
创建表的基础SQL语法如下:
CREATE TABLE <表名> (<列名> <列的数据类型> [<列的约束>]);
其中,表名在一个数据库中必须是唯一的,并且符合标识符规则。列名在一个表内必须是唯一的,并且符合标识符规则。列的数据类型决定了什么样的数据可以存储在列中,而列的约束定义了创建列时的限制条件。
举例:
CREATE TABLE Friend (Name VARCHAR(50), PhoneNo VARCHAR(15));
删除表
删除表的基础SQL语法如下:
DROP TABLE <表名>;
通过外键约束连接在一起的表不能被删除。在删除表之前,必须先删除约束。在删除表时,我们必须是表的所有者或者对该表有管理员权限。
复制表
在MySQL中,下面的语句创建一个名为My_Friends的新表,该表是复制了Friend表的数据和结构(列、数据类型):
CREATE TABLE My_Friends SELECT * FROM Friend;
复制表的同时表的约束并不能复制过来。所以,推荐使用CREATE TABLE语句创建基本的列和数据类型,然后使用ALTER TABLE命令添加所有其它约束。
如果是只复制表结构,不复制数据,只需要在WHERE子句中添加一个永远不等于true的条件即可。
CREATE TABLE My_Friends SELECT * FkROM Friend WHERE 1=0;
修改表
添加新列:
ALTER TABLE Friend ADD Address VARCHAR(50);
更改列:
ALTER TABLE Friend CHANGE Phone Phone VARCHAR(11) DEFAULT(‘不知道电话号码‘);
删除列:
ALTER TABLE Friend DROP COLUMN PhoneNo;
创建索引
CREATE INDEX <索引名> ON <表名>(<列名一>,[<列名二>],…);
举例:
create index index_name on student(Name)
删除索引
删除索引的SQL命令是DROP INDEX。但是确切的语法取决于数据库厂商。MySQL数据库采用修改表的方式删除索引。
CREATE INDEX <索引名> ON <表名>(<列名一>,[<列名二>],…);
保证数据完整性
数据库完整性概述
为什么要保证数据库完整性?
为了防止垃圾数据的产生,从而影响数据库的执行效率!!!
数据完整性的概念
可靠性 + 准确性 = 数据完整性
数据完整性的分类
1.实体完整性
保证一行数据是有效的
2.域完整性
保证一列数据是有效的
3.引用完整性
保证引用的编号是有效的
4.用户自定义完整性
保证自定义规则
实体完整性
为什么要保证实体完整性
保证每行所代表的实体能互相区别
什么是实体完整性
表中的一行数据如果与它所代表的实体完全一致,则具备实体完整性。
实现方法
主键约束(Primary Key)
主键(Primary Key)是表中的一到多个列,主键列不能为空,也不能重复。
唯一约束(Unique)
唯一约束是指给定列的所有值必须唯一,该列在表中每一行的值必须唯一。它和主键约束的区别在于该列可以为空,并且可以在一张表中给多个列设置唯一约束。
设置主键约束
设置主键约束可以在创建表时指定,例如:
CREATE TABLE t_student( s_id INT PRIMARY KEY, -- 指定主键约束 s_name VARCHAR(50) NOT NULL)
或
CREATE TABLE t_student_bak( s_id INT , s_name VARCHAR(50) NOT NULL, PRIMARY KEY(s_id)-- 指定主键约束)
设置唯一约束
设置唯一约束可以在创建表时指定,例如:
CREATE TABLE t_student( s_id INT PRIMARY KEY, s_name VARCHAR(50) UNIQUE NOT NULL )
域完整性
为什么要域完整性
保证指定列的数据的有效性
什么叫域完整性
域完整性是指定列的输入有效性
实现方法
非空约束:Not Null
默认约束:Default
检查约束:Check(MySQL不支持)
设置非空约束
设置非空约束可以在创建表时指定,例如:
CREATE TABLE t_student( s_id INT PRIMARY KEY, s_name VARCHAR(50) UNIQUE NOT NULL, s_age INT NOT NULL )
注意:主键约束默认为非空
设置默认约束
设置默认约束可以在创建表时指定,例如:
CREATE TABLE t_student( s_id INT PRIMARY KEY, s_name VARCHAR(50) UNIQUE NOT NULL, s_age INT, s_gendar CHAR(2) DEFAULT ‘男‘)
设定了默认值后,可以再添加此列时不指定值,或使用default关键字让数据库自动填充设定的默认值。
下面两条SQL语句均可使用默认值:
INSERT INTO t_student VALUES(1,‘阿强‘,20,DEFAULT); INSERT INTO t_student(s_id,s_name,s_age) VALUES(2,‘阿呆‘,21);
设置受检查约束
受检查约束是最灵活的约束类型,它允许我们再更改或插入行到数据库时有一个较宽访问的限制。比如设置只允许插入年龄大于18岁的数据,
如:s_age INT check(s_age>18) 但是在MySQL数据库中没有提供对该约束的支持。
引用完整性---外键约束
为什么要引用完整性约束
例如,在录入学生成绩时,所使用的学号必须是在学生表中作为主键存在的编号。
什么叫引用完整性
参照完整性是指分布在两个表中的列所满足的具有主从性质的约束关系。
方法: 外键约束
外键与外键约束
二者是不同概念,常常被混淆 外键是指从表的某列与主表的某列存在依附关系,比如学生表与班级表啊,学生表中有一列为班级编号,此列与班级表的班级编号相对应。此关系是设计这两张表时根据业务而建立的,此时我们可以认为学生表有一个外键与班级表的主键相关联,但是此关系并没有强制性依赖。
外键约束是指在外键关联主键上强制加上一个约束,如果违反该约束,则不允许该条数据的修改。
注意:没有建立外键约束不等于没有外键
设置外键约束
设置默认约束可以在创建表时指定,例如:
--先创建主表
CREATE TABLE t_class( c_id INT PRIMARY KEY, c_name VARCHAR(50) UNIQUE NOT NULL )ENGINE=INNODB
--再创建从表(外键所在的表) CREATE TABLE t_student( s_id INT PRIMARY KEY, s_c_id INT REFERENCES t_class(c_id), s_name VARCHAR(50) UNIQUE NOT NULL, s_age INT, s_gendar CHAR(2) DEFAULT ‘男‘, CONSTRAINT FOREIGN KEY(s_c_id) REFERENCES t_class(c_id) )ENGINE=INNODB
注意:MySQL中必须要给有外键约束的表设置其表类型为InnoDB。
自定义完整性
用户定义完整性使我们可以定义不属于其它任何完整性分类的特定业务规则。
所有的完整性类型都支持用户定义完整性(CREATE TABLE 中的所有列级和表级约束、存储过程和触发器)。
使用自动编号
在MySQL数据库中,提供了一种自动为列产生数值的机制。这种自动产生值的字段通常与主键约束一起配合使用。
MySQL使用auto_increment来实现列的自增长,例如:
CREATE TABLE t_class( c_id INT PRIMARY KEY AUTO_INCREMENT,--定义自增长 c_name VARCHAR(50) UNIQUE NOT NULL )ENGINE=INNODB
--增加数据时可以不为自增长列设定值 INSERT INTO t_class(c_name) VALUES(‘t01‘);
MySQL中,自增长序号是从1开始,每次递增1。也可以通过下面的代码设置起始序号:
ALTER TABLE t_class AUTO_INCREMENT=100000
修改数据完整性
我们不仅可以使用ALTER TABLE添加或者删除列,也可以添加、删除主键、外键或其他约束。下面我们为一个已存在的表中删除一个UNIQUE约束,同时添加一个主键约束:
CREATE TABLE t_class( c_id INT, c_name VARCHAR(50) UNIQUE NOT NULL, CONSTRAINT unq_name UNIQUE(c_name) );
--删除唯一约束 ALTER TABLE t_class DROP INDEX unq_name;
--增加主键 ALTER TABLE t_class CHANGE c_id c_id INT,ADD PRIMARY KEY(c_id);
使用DML语句更改数据
添加新数据
插入单行记录
向表中添加数据的SQL语句是INSERT
基本语法:
INSERT INTO <表名> (<列名列表>) VALUES (<值列表>)
举例
向学生表添加记录
表 结构
CREATE TABLE t_student(
学号 INT PRIMARY KEY,
姓名 VARCHAR(50) NOT NULL,
年龄 INT,
性别 CHAR(2)
)
插入单行记录
插入一条数据
INSERT INTO t_student(学号,姓名,年龄,性别) VALUES(1,‘张三‘,25,‘男‘)
也可以省略列名
INSERT INTO t_student VALUES(1,‘张三‘,25,‘男‘)
省略掉列名后,要求插入的值必须和表中的列一一对应。
也可以使增加的数据列与表中列不匹配,但是必须要在增加语句中指定插入列。比如增加一条记录,只包含学号和姓名:
INSERT INTO t_student(学号,姓名) VALUES(1,‘张三‘)
在下面几种情况下可以省略某些列:
列值由RDBMS自动创建,如自增长。
创建列时设定了默认值,如果不提供值,则由RDBMS自动创建。
如果列被设置为允许空值,那么不输入值不影响数据库的完整性。
插入多行记录
插入多行记录是指一条SQL语句实现多条记录的插入,实现方式有两种:
1.SELECT方式
INSERT INTO <表名> (<列名列表>) SELECT <Select语句>;
这种方式利用SELECT语句(查询)代替values。通过查询语句将查询的结果插入到表中。要求查询语句的选择列要和插入语句指定列对应。
2.多行VALUES插入
INSERT INTO t_student VALUES (1,‘张三‘,20,‘男‘), (2,‘李四‘,25,‘男‘), (3,‘王五‘,19,‘女‘)
此方法可以在VALUES后跟多条记录,但是此方法仅限于在MYSQL数据库中使用。
表数据的复制
在测试数据时,我们经常会为了避免误操作数据而采取一些保护措施,如数据备份。数据备份的一种常见的操作就是从一张表复制数据到备份表中。在MySQL中可以通过以下几种方式实现赋值表数据:
1.INSERT INTO的方式复制
INSERT INTO t_student_bak SELECT * FROM t_student
2.建表的方式复制
CREATE TABLE t_student_bak SELECT * FROM t_student
更改已有数据
标准结构
UPDATE 表名 SET 列1=新值1,列2=新值2 WHERE 过滤条件
SET语句就是指定修改的列,修改多个列时用逗号分开。
如果要将某列值删除,只需要将该列的数据设置为NULL即可。下面分别介绍几种更新方式。
更新单列数据
举例
更新张三同学的性别为女
UPDATE t_student SET 性别=‘女’ WHERE 姓名=‘张三’
将所有年龄小于18岁的同学增加3岁
UPDATE t_student SET 年龄=年龄+3 WHERE 年龄<18
注意:忽略WHERE子句将会改变表中所有行!
更新多列数据
举例
更新张三同学的年龄为100岁,并将其姓名改为张三丰
UPDATE t_student SET 姓名=‘张三丰‘,年龄=100 WHERE 姓名=‘张三‘
通过更新删除列中的数据
如果要删除某列的值,只需要将该列设置为NULL即可。当然,这样做的前提是该列允许为空,即没有非空约束。
举例
将李四的性别删除
UPDATE t_student SET 性别=NULL WHERE 姓名=‘李四‘
注意删除列值只是将该列的值置为空,而不是将该列从表中去掉。如果要去掉该列应该使用DDL语句。
删除数据
使用DELETE删除行
标准结构
DELETE FROM 表名 WHERE 过滤条件
删除语句可以删除一行或多行,根据过滤条件来确定。
举例
删除姓名为张三的学生信息
DELETE FROM t_student WHERE 姓名=‘张三’
删除年龄18-20岁之间的学生信息
DELETE FROM t_student WHERE 年龄 BETWEEN 18 AND 20
删除所有数据
使用DELETE删除
不加WHERE条件的DELETE语句就能删除所有数据
使用TRUNCATE语句
直接删除表中所有数据
标准结构
TRUNCATE TABLE 表名
二者的区别
DELETE会记录日志,意味着删除后的数据还可以恢复,但是效率低。TRUNCATE不会记录日志,删除后的数据不能恢复,但是效率高。TRUNCATE不能用于有外键约束引用的表。
简单的数据查询
查询的基本结构
概念
查询(DQL)是数据库中最为常用和复杂的一种SQL结构,学会编写查询SQL是程序员必须具备的能力。
要从数据库中查询数据,我们要使用SQL的SELECT语句。标准SELECT查询由SELECT子句、FROM子句、WHERE子句、ORDER BY子句组成。
标准结构
SELECT [DISTINCT] {* | 列名 [别名], …} FROM 表名 [WHERE 过滤条件] [ORDER BY 列1,列2…]
查询操作的分类
投影操作
指定查询结果中能显示哪些列
选择操作
指定哪些行出现在结果中
排序操作
指定查询的结果以什么样的顺序显示
投影操作
概念
投影操作是查询语句里必须有的子句,关键字则为SELECT。它将选择对表中哪些列进行操作,这些列将出现在结果中。
标准结构
SELECT 列1,列2 FROM 表名
列表名的几种书写方法:
如果我们选择某个表中的多个列,那么列名之间用逗号分隔开;
如果是单个列,只需要列出该列的列名即可;
如果选择所有的列,可以简单地用“*”号带代替列名列表。
表前缀
SELECT t_student.姓名 FROM t_student
列别名
使用别名,可以使SQL语句和返回的数据更容易读懂、更容易理解。在多个表有同样的列名的时候,使用别名更容易区分。
在列名或表名用AS关键字来提供别名,语法如下:
SELECT 列A AS A, 列B AS B, 列C AS C FROM 表名 AS T
当使用表的别名时,可以在同一SQL语句中的列名使用别名,例如:
SELECT T.列A AS A, T.列B AS B, T.列C AS C FROM 表 AS T
计算列
在数据库管理系统中,我们也可以执行返回计算列的SELECT查询。返回计算列意味着数据不存在于数据库中,但是可以从数据库中的数据构造或者计算得来。
举例
将每个学生年龄加上10岁显示
SELECT 年龄+10 FROM t_student
投影列也可以用字符串连接,MySQL中字符串连接用CONCAT函数,如
SELECT CONCAT(姓名,’-’,年龄) FROM t_student
排除重复数据
数据库表的同列中,经常有相同值多次出现。有时,我们需要确保返回唯一的数据行。这时我们需要使用DISTINCT关键字来排除重复的行数据。
标准结构
SELECT DISTINCT 列1 FROM 表名
SELECT DISTINCT 性别 FROM t_student
结果只有2条数据,重复的数据不显示。
返回限定行数的查询
在MySQL中可以限制查询的行数,并制定从第几行开始到第几行结束。
标准结构
SELECT 列1,列2 FROM t_student LIMIT 开始序号 , 返回的行数
如果用1个参数,则表示从第一行开始返回指定行数的结果。
如果用2个参数,则表示从指定行开始返回指定行数的结果。
注意:LIMIT序号是从0开始。LIMIT只能用于MySQL中。
选择操作
单条件选择操作
WHERE子句应用搜索条件于SELECT查询获得的数据,搜索条件可以采用不同的形式,但是条件的值都是布尔值。在此情况下,我们只对“列C = 值”为真的行感兴趣。如果条件为真,行就被返回;如果为假或者UNKNOWN(因为NULL值的存在),则被忽略。
标准结构
SELECT 列1, 列2 FROM 表 WHERE 列3 = 值
举例
查询姓名为张三同学的所有信息
SELECT * FROM t_student WHERE 姓名=‘张三’
还有哪些条件?
运算符 含义
= 用于检测值是否于另一个值相等
!= 用于检测值是否不等于另一个值
^= 与!=类似
<> 与!=类似
> 如果第一个操作数大于第二个操作数则为真
>= 用于检测第一个操作数是否大于或者等于第二个操作数
< 如果第一个操作数小于第二个操作数则为真
<= 用于检测第一个操作数是否小于或者等于第二个操作数
多条件选择操作
组合WHERE条件
AND:并且
OR:或者
标准结构
SELECT 列A, 列B FROM 表 WHERE 条件1 (and 或者 or) 条件2
举例
查询年龄在18岁以下或25岁以上的同学信息。
SELECT * FROM t_student WHERE 年龄<18 OR 年龄>25
查询年龄在18-25岁之间的女生信息。
SELECT * FROM t_student WHERE 年龄>=18 AND 年龄<=25 AND 性别=‘女‘
执行范围测试(BETWEEN)
一个范围搜索,大于等于下限,并且小于等于上限。
标准结构
SELECT 列A, 列B FROM 表 WHERE 列C BETWEEN 下限 AND 上限
举例
查询年龄在18到25岁之间的学生信息
SELECT * FROM t_student WHERE 年龄 BETWEEN 18 AND 20
定义集合关系(IN或NOT IN)
在指定的某几个值中进行搜索
标准结构
SELECT 列A, 列B FROM 表 WHERE 列C IN (值集合)
举例
查询年龄在18、20、22岁三个年龄段的学生信息
SELECT * FROM t_student WHERE 年龄 IN(18,20,22)
如果改成NOT IN,则搜索不在18、20、22三个年龄段的学生。
模糊查询(LIKE)
模糊查询是一种比较实用的过滤方式,利用通配符来实现模糊查询。
标准结构
SELECT 列A, 列B FROM 表 WHERE 列C LIKE 模式
通配符
“_”通配符
表示任何单个字符
“%”通配符
表示包含零个或多个任意字符
举例
查询名字为两个字的学生信息
SELECT * FROM t_student WHERE 姓名 LIKE ‘__‘
查询姓张的学生信息
SELECT * FROM t_student WHERE 姓名 LIKE ‘张%‘
处理空值数据
在数据库中判断某列是否为空不能用=NULL,而应该用IS NULL或IS NOT NULL。使用其他任何比较运算符来匹配NULL得到的都是FALSE的结果,比如NULL=NULL也是返回FALSE。
举例
查看性别为空的学生信息
SELECT * FROM t_student WHERE 性别 IS NULL
排序操作
概念
排序操作是指当查询的结果投影出来后以哪一列或及列的顺序进行排列。如果不指定则以数据库默认顺序排列。
标准结构
单列排序
SELECT 列A, 列B, 列C FROM 表 ORDER BY 列A
其中,ORDER BY子句指定列A用于对数据排序,列A的值可以是字母、数字、时间等。
多列排序
SELECT 列A, 列B, 列C FROM 表 ORDER BY 列A, 列B, 列C...
在ORDER BY子句后指定多个列名时,是根据后面列名的顺序确定优先级。
基本查询SQL的执行顺序
要学好查询SQL就必须掌握SQL的执行顺序,目前我们已经学习了SELECT、FROM WHERE、ORDER BY这几个关键字的用法,他们组成了基本查询SQL的结果,下面是他们的执行顺序。
第一步:执行FROM
第二步:WHERE条件过滤
第三步:执行SELECT投影列
第四步:执行ORDER BY 排序
聚合函数与分组
使用聚合函数进行统计汇总
概述
在查询分析的SQL中我们经常会对一些数据进行统计查询。比如统计某个班有多少个学生、全班总分多少、平均分多少、最高分是多少、最低分是多少。要实现这些数据的统计就需要要用到SQL提供的聚合函数。
聚合函数的分类
COUNT:统计行数量
SUM:获取单个列的合计值
AVG:计算某个列的平均值
MAX:计算列的最大值
MIN:计算列的最小值
执行行和列计数(COUNT)
行计数可以统计返回的结果中有多少行数据
标准结构
SELECT COUNT(<计数规范>) FROM <表名>
计数规范
* 计数所有选择的行,包括NULL值
ALL 列 计数指定列的所有的非空值行。如果仅仅是指定列而不带ALL或者DISTINCT,这是默认操作。
DISTINCT 列 计数指定列的所有唯一非空值行。
计数规范(*)
* 表示统计所有行,包括NULL值。
举例
统计班上一共有多少个学生
SELECT COUNT(*) FROM t_student
也可以加入查询条件。例如:统计男生有多少人?
SELECT COUNT(*) FROM t_student WHERE 性别=‘男’
计数规范(ALL)
ALL表示统计指定列所有非空值的行数。
举例
为学生表添加班级字段,报名注册的同学都会将其分配到某个班上。如果仅仅是入学还没登记注册的同学则暂时没有班级,班级字段的值为空。
查询已报名注册的同学又多少人
SELECT COUNT(ALL 班级) FROM t_student
这个练习就不能用*,因为*是统计返回结果中的所有行,有些同学还没报名则不能统计出来。使用ALL后可以统计指定列的所有非空的行数。有些同学没有报名,班级字段就为空,使用ALL就会把这些为空的数据排除掉。ALL可以省略,默认就是ALL。
计数规范(DISTINCT)
DISTINCT表示统计指定列所有非空值,且不重复数据的行数。
举例
DISTINCT和ALL唯一区别就是DISTINCT会排除重复。
统计班上有多少个年龄段同学。
SELECT COUNT(DISTINCT 年龄) FROM t_student
班上年龄段学生有很多,比如有18岁、19岁、22岁等等,其中18岁有3人、18岁有2人、22岁有1人。统计年龄段就要排除重复,剩下结果为3个年龄段。
返回列合计值(SUM)
SUM函数用于统计某列数值的总和。
标准结构
SELECT SUM(<计数规范>) FROM <表名>;
SUM只有ALL和DISTINCT这两种计数规范,没有*。
举例
查询班上学生年龄的总和。
SELECT SUM(ALL 年龄) FROM t_student
如果某人的年龄为空则不会被统计在内,也可以省略ALL关键字,默认为ALL。如果改为DISTICT则只会统计不重复的年龄。
获取列平均值(AVG)
AVG函数用于统计某列数值的平均值。
标准结构
SELECT AVG(<平均值规范>) FROM <表名>;
AVG只有ALL和DISTINCT这两种平均值规范,没有*。
举例
查询班上学生的平均年龄。
SELECT AVG(ALL 年龄) FROM t_student
如果有个人的年龄为空,则AVG会以9个人的年龄总和除以9,而不是除以10.这样算出来的平均值会略大。如果要正确计算,可以使用SUM(年龄)/COUNT(*)的方式。 AVG也可以省略ALL关键字,默认为ALL。如果改为DISTICT则只会统计不重复的年龄。
返回最大值和最小值(MAX/MIN)
MAX函数返回某列中的最大值
MIN函数返回某列中的最小值
标准结构
SELECT MAX(<列名>) FROM <表名> SELECT MIN(<列名>) FROM <表名>
MAX/MIN没有ALL、DISTINCT、*这些规范
举例
显示班上最大的年龄和最小的年龄
SELECT MAX(年龄) AS 最大年龄 , MIN(年龄) AS 最小年龄 FROM t_student
数据分组
概述
到目前为止,我们仅仅是在一个表中的所有行或者过滤行集合中应用聚合函数。如果我们想要获得数据集合中的子集的总计值,可能需要好几个单独的查询。例如,我们要统计每个班上有多少人,那么我们需要写两个查询语句:
SELECT COUNT(*) FROM t_student WHERE 班级=‘T01’ SELECT COUNT(*) FROM t_student WHERE 班级=‘T02’ ……
班级越多,SQL就会越多,显然这并不是一种理想的做法。SQL提供了一种技术,可以将表中的行分组,然后在每个组上应用聚合函数。这种分组技术与聚合函数一起使用时,功能尤为强大
过滤分组数据
标准结构
SELECT 列A, 聚合函数(聚合函数规范) FROM 表名 WHERE 过滤条件 GROUP BY 列A …
分组GROUP BY子句是在WHERE条件过滤后的结果中完成,如果没有WHERE条件则直接对FROM表中的数据进行分组。
举例
统计每个班级年龄在18岁以上的学生人数
SELECT 班级 , COUNT(*) AS 人数 FROM t_student WHERE 年龄>18 GROUP BY 班级
GROUP BY会将指定列中有相同数据的分为一组。例子中用了班级进行分组,相同的班级会被分到一组。再对每组分别执行聚合。
多列分组
分组可以实现多列分组,比如按班级和年龄分组,那么只有当班级和年龄一样的才分一组,例如:
SELECT 班级 , 人数 , COUNT(*) AS 人数 FROM t_student GROUP BY 班级 , 年龄
在有分组的SQL语句中,投影的列就会有限制。要求SELECT中的列必须满足以下两个条件之一,否则就是无效的投影。
1.使用了聚合函数的列
2.该列在GROUP BY 子句中
使用HAVING子句
假设我们想对聚合后的数据进行过滤,例如,查询平均年龄在20岁以上的班级信息。
思考
能用下面的SQL查询吗?
SELECT 班级 , AVG(年龄) FROM t_student WHERE AVG(年龄)>20 GROUP BY 班级
上面SQL执行时会出错。原因是聚合是在分组后进行的,WHERE子句是在分组前执行的,所以在WHERE子句里执行聚合函数是不行的。SQL提供了另外一个关键字HAVING来实现聚合函数的过滤。HAVING子句是在GROUP BY后执行的。
标准结构
SELECT 列A, 聚合函数(聚合函数规范) FROM 表名 WHERE 过滤条件 GROUP BY 列A HAVING 过滤条件
举例
查询平均年龄在20岁以上的班级信息
SELECT 班级 , AVG(年龄) FROM t_student GROUP BY 班级 HAVING AVG(年龄)>20
HAVING和WHERE区别
二者都是过滤条件,WHERE运行在分组前,因此不能执行任何聚合函数。HAVING是运行在分组后,只能用做聚合函数的过滤。
SQL执行顺序
在基本的SQL学习中我们已经掌握到了SQL执行顺序,下面来看看加上分组后的SQL的执行顺序
第一步:执行FROM
第二步:WHERE条件过滤
第三步:GROUP BY分组
第四步:执行SELECT投影列
第五步:HAVING条件过滤
第六步:执行ORDER BY 排序
子查询和组合查询
使用子查询
什么是子查询?
嵌套在主查询中的查询——子查询。
也就是说子查询是嵌套在查询语句里面的查询语句,就像语句块里嵌套语句块类似。
子查询的简单形式:
SELECT ColumnA, (子查询) AS ColumnB FROM 表名;
如何使用子查询
可以在哪些位置嵌套子查询呢?
下面我们看看一个完整的SQL结构:
SELECT 列1,列2,...
FROM 表1,表2,...
WHERE 列1=值,...
GROUP BY 列1,列2,...
HAVING 聚合函数(列1)=值,...
ORDER BY 列1,列2,...
在完整的SQL结构中能嵌套子查询的位置分别是SELECT、FROM、WHERE、GROUP BY 、HAVING、ORDER BY。
子查询嵌套位置
SELECT中嵌套
FROM 中嵌套
WHERE中嵌套
GROUP BY中嵌套
HAVING中嵌套
ORDER BY中嵌套
在SELECT中嵌套
标准结构
SELECT 列1, (子查询) AS 别名 FROM 表名
问题:查询学生信息及所在班级名称?
班级信息和学生信息来自不同的表。
SQL语句
SELECT 学号,姓名,科目, (SELECT 班级名称 FROM t_class c WHERE c.班级编号=s.班级编号) 名称 FROM t_student s
嵌套在SELECT语句中SQL语句要求查询的值只能是单行和单列。
在FROM中嵌套
标准结构
SELECT 列1,列2 FROM (子查询) AS 别名
From里的子查询可以是任意查询语句,然后将其结果作为外部查询的表。比如:
SELECT * FROM (SELECT 学号,姓名 FROM t_student) s
上面的SQL语句虽然作用不大,但其说明FROM中嵌套的SQL不受任何限制,也就是说子查询结果可以为多行多列。
在WHERE中嵌套
标准结构
SELECT 列1,列2 FROM 表 WHERE 列=(子查询)
在WHERE中嵌套的子查询根据不同的运算符有不同的分类:
比较运算符(>、<、=、>=、<=、!=)
in 和not in运算符
子查询运算符(ALL、ANY、 EXISTS)
比较运算符(>、<、=、>=、<=、!=)
问题:查询比张三的C语言成绩高的其他学生成绩信息。
分析:首先需要知道张三的C语言成绩多少分,这个可以作为一个查询。然后用外部成绩与此成绩做一个比较即可,即:
SELECT * FROM t_student WHERE 分数>(SELECT 分数 FROM t_student WHERE 姓名=‘张三‘ AND 科目=‘C语言‘) AND 姓名!=‘张三‘
在比较运算符的表达式中可以使用子查询,这个子查询要求返回的结果只能 是单列和单行。
in运算符
问题:查询和张三同学考同样分数的学生信息
分析:首先需要知道张三同学考了哪些试,分数多少。在外部查询中过滤哪些分数和子查询的分数相同,例如:
SELECT * FROM t_student WHERE 分数 IN (SELECT 分数 FROM t_student WHERE 姓名=‘张三‘) AND 姓名!=‘张三‘
使用IN运算符时,如果表达式中有子查询,则该子查询的结果为单列,可以为单行或多行。
not in 运算符
问题:哪个班级没有学生加入?
分析:将每个学生所在的班级编号查出,然后利用not in排除这些数据就得到没有学生的班级,例如:
SELECT * FROM t_class WHERE 班级编号 NOT IN (SELECT 班级编号 FROM t_student )
使用NOT IN运算符时,如果表达式中有子查询,则该子查询的结果为单列,可以为单行或多行。
ALL运算符
和子查询的结果逐一比较,必须全部满足时表达式的值才为真。
ANY运算符
和子查询的结果逐一比较,其中一条记录满足条件则表达式的值就为真。
EXISTS/NOT EXISTS运算符
EXISTS判断子查询是否存在数据,如果存在则表达式为真,反之为假。NOT EXISTS相反。
ALL运算符
问题:查询比张三的所有成绩都要高学生成绩信息。
分析:首先查询出张三考的所有科目成绩,然后利用ALL运算符逐一比较,如果某科学生成绩比所有的成绩都大则满足条件,例如:
SELECT * FROM t_student WHERE 分数 >ALL (SELECT 分数 FROM t_student WHERE 姓名=‘张三‘ )
使用ALL运算符时要求其中子查询返回的结果是单列,可以为单行或多行。
ANY运算符
问题:查询比张三的某一个科成绩高的其他学生。
分析:ANY和ALL区别就在于子查询中只有一条记录满足就行,例如:
SELECT * FROM t_student WHERE 分数 >ANY (SELECT 分数 FROM t_student WHERE 姓名=‘张三’ ) AND 姓名!=‘张三’
使用ANY运算符时要求其中子查询返回的结果是单列,可以为单行或多行。 思考:刚才的两个例子如果不用ALL或ANY该如何实现?
EXSITS/NOT EXSITS运算符
问题:查询和张三同学考同样分数的学生信息。
分析:沿用之前IN的例子,二者可以互换,例如:
SELECT * FROM t_student s1 WHERE EXISTS(SELECT * FROM t_student s2 WHERE 姓名=‘张三‘ AND s1.分数=s2.分数) AND 姓名!=‘张三‘
使用EXISTS运算符时只要子查询有数据则表达式为真,因此子查询的结果是单列或多列、单行或多行都行。 思考:NOT IN使用的例子如何用NOT EXISTS实现。
在GROUP BY 中嵌套
GROUP BY中嵌套和SELECT中嵌套类似,要求子查询只能返回单行单列值。
在HAVING中嵌套
HAVING中嵌套子查询和WHERE中嵌套子查询类似,只是能用到聚合函数。
在ORDER BY 中嵌套
ORDER BY中嵌套子查询和SELECT中嵌套子查询类似,要求子查询只能返回单行单列值。
上面三个位置嵌套子查询实际作用不大,因此很少会用到。
子查询分类
相关子查询
执行依赖于外部查询的数据。
外部查询返回一行,子查询就执行一次。
非相关子查询
独立于外部查询的子查询。
子查询总共执行一次,执行完毕后后将值传递给外部查询。
相关子查询通常要消耗更长的执行时间,当数据量增加时,执行时间会急剧增加。
组合查询
使用UNION运算符
UNION是一种联合两条或以上查询的运算符,类似多条查询结果相组合的效果。
标准结构
SELECT 列1 , 列2 FROM 表1 UNION SELECT 列3 , 列4 FROM 表2;
UNION 的结果集列名与 UNION 运算符中第一个 SELECT 语句的结果集中的列名相同。另一个 SELECT 语句的结果集列名将被忽略。
使用UNION ALL运算符
UNION ALL会保留重复行
标准结构
SELECT 列1 , 列2 FROM 表1 UNION ALL SELECT 列3 , 列4 FROM 表2;
联接
为什么使用表联接
思考
查询每个学生所在的班级名称?
分析
班级和学生信息在不同的表中,我们可以使用子查询来实现,如:
SELECT 学号,姓名,科目,(SELECT 班级名称 FROM t_class c WHERE c.班级编号=s.班级编号) FROM t_student s
上面用到了相关子查询,效率低下。
什么是表联接
如果数据来自多个表,那么可以采用联接查询的方式来实现。因此表联接就是指将多个表联合在一起实现查询效果。
表联接的原理
将多个表联接在一起和之前组合查询的UNION完全不同,UNION是将多个查询结果组合在一起,称之为纵向联接。表联接采用的是笛卡尔乘积,称之为横向联接。
表联接原理
笛卡尔乘积
表联接的基本原理就是采用笛卡尔乘积。笛卡尔乘积是指将两张表的所有数据相连,最后联接的结果数为两张表数量的乘积。
使用表联接
如何实现表联接
从上面图示可以看出表联接是将两张表的数据相乘而得到的结果,第一张表的每条记录都会和第二张表的所有记录相连。
在数据库中将多表相连需要使用JOIN关键字。
标准结构
SELECT 列1,列2 FROM 表1 JOIN 表2
笛卡尔乘积出来的结果数量太多,其中有不少数据是没用的。因为我们在建表时为了表示他们的关系,都会建立外键来确定关系,所以在表联接时就要根据其外键来过滤没用的数据。使用ON关键字来确定其是否匹配。
完整结构
SELECT 列1,列2 FROM 表1 JOIN 表2 ON 表1.列=表2.列
练习
查询所有学生信息及所在的班级名称
SELECT 学号,姓名,科目,c.班级名称 FROM t_student s JOIN t_class c ON s.班级编号=c.班级编号
两表联接时经常出现不同表有相同列名,因此尽量使用别名来区分。
练习
查询属于班级T01下的学生信息
分析
这个练习多了t01这个条件,表联接的SQL语句中仍然可以使用条件过滤。
SELECT 学号,姓名,科目,c.班级名称 FROM t_student s JOIN t_class c ON s.班级编号=c.班级编号 WHERE c.班级名称=‘T01‘
当多表联接上后,就可以像操作一张表时一样了。
表联接分类
内联接
外联接
自联接
内联接
内联接是指使用比较运算符根据每个表共有的列的值匹配两个表中的行。
在上两个练习中我们使用的联接均为内联接,因为学生表的班级编号和班级表中班级编号必须一样时这条记录才会出现在结果中。
内联接的标准语法是INNER JOIN,INNER可以省略,例如:
SELECT 学号,姓名,科目,c.班级名称 FROM t_student s INNER JOIN t_class c ON s.班级编号=c.班级编号
内联接的另一种实现
内联接出了用INNER JOIN ON外还可以使用更为简单的方式,例如:
SELECT 学号,姓名,科目,c.班级名称 FROM t_student s , t_class c WHERE s.班级编号=c.班级编号
这种方式是直接在FROM中用逗号来分隔多个表,从而实现联接,过滤条件写在WHERE语句中。这种方式和INNER JOIN是等价的。
外联接
定义
外联接是指不管有没有匹配,被定义了外联接的表数据都要出现在结果中。比如左外联接,那么在JOIN左边的表就被定义为外联接,那么此表中所有数据都会出现在查询结果中。右外联接则是JOIN右边的表为外联接表。全外联接就是JOIN左右两张表都是外联接表。
分类
左外联接
用法:LEFT OUTER JOIN 或 LEFT JOIN
右外联接 用法:RIGHT OUTER JOIN 或 RIGHT JOIN
全外联接 用法:FULL OUTER JOIN 或 FULL JOIN
注意:MYSQL不支持全外联接
问题
查询所有学生信息及其所在班级名称,还没分配班级的学生也要显示。
分析
有些学生刚入学还没分配班级,因此在他的班级记录为空。如果用内联接则这条数据会被过滤掉,因为班级表没有和他匹配的数据。此时就要使用外联接。
SELECT 学号,姓名,科目,c.班级名称 FROM t_student s LEFT JOIN t_class c ON s.班级编号=c.班级编号
例子中用到左外联接LEFT JOIN,这是因为学生表在JOIN的左边,如果把学生表和班级表的位置换下就成右外联接。
练习
查询有哪些班级还没有学生?
要求
不用子查询,用表联接实现。
SELECT c.班级名称 FROM t_student s RIGHT JOIN t_class c ON s.班级编号=c.班级编号 WHERE s.学号 IS NULL
自联接
定义
自联接其实就是内联接或外联接的一种特例,同样可以使用INNER JOIN 或 OUTER JOIN。
自联接所联接的表是来自于同一张表。
举例
一张存放员工信息的表,每个员工有个直属领导。当然直属领导也是员工,所以员工信息和他们的领导信息都再一张表中。下面是表结构:
CREATE TABLE t_emp( 员工编号 INT, 员工姓名 VARCHAR(50), 领带编号 INT)
练习
查询每位员工姓名及他们直属领导的姓名。
分析
每位员工都有其直属领导的编号,可以想象成有张领导表,这一列就是指向领导表的外键。
SELECT e.员工姓名,l.员工姓名 AS 领导姓名 FROM t_emp e JOIN t_emp l ON e.领导编号=l.员工编号
联接的两张表都是t_emp,但是左边是员工表,右边则想象成领导表,分别为他们定义不同的别名用以区分。
标签:
原文地址:http://www.cnblogs.com/lxh1197412986/p/4721035.html