10.3 SQL语法

目录

  • 一、关系数据库基本概念和MySQL基本命令

    • 1.1 数据库的概念和类型分类
    • 1.2 MySQL数据库的命令
    • 1.3 MySQL数据库的存储机制
  • 二、SQL语句基础
  • 三、DDL语句
    • 3.1 创建表的语法
    • 3.2 修改表结构语法
    • 3.3 删除表的语法
    • 3.4 truncate表
  • 四、数据库约束
    • 4.1 NOT NULL约束
    • 4.2 UNIQUE约束
    • 4.3 PRIMARY KEY约束
    • 4.4 FOREIGN KEY约束
    • 4.5 CHECK约束
  • 五、索引
    • 5.1 创建索引
    • 5.2 删除索引
  • 六、视图
    • 6.1 创建视图
    • 6.2 删除视图的语句
  • 七、DML(Data Manipulation Language)语句语法
    • 7.1 insert into插入记录
    • 7.2 update语句——修改表记录
    • 7.3 delete from删除语句
  • 八、单表查询
    • 8.1 基本语法说明
    • 8.2 where语句选出特定行
    • 8.3 在select语句中使用算术运算符(+、-、*、/)
    • 8.4 concat()函数进行字符串连接运算
    • 8.5 算数表达式现null值
    • 8.6 为数据列或表达式取别名
    • 8.6 为表名取别名
    • 8.7 在select、where中都不出现列名
    • 8.8 distinct去重
    • 8.9 where子句中的比较运算符
    • 8.10 where子句中的条件组合
    • 8.11 比较运算符、逻辑运算符的优先级
    • 8.12 执行查询后的结果排序
  • 九、数据库函数
    • 9.1 单行函数
    • 9.2 分组和组函数
  • 十、多表连接查询
    • 10.1 SQL 92连接查询

      • 1、多表连接语法格式
      • 2、等值连接
      • 3、非等值连接
      • 4、广义笛卡尔积
      • 5、其它用法
    • 10.2 SQL 99的连接查询
      • 1、交叉连接(cross join)
      • 2、自然连接(natural join)
      • 3、using子句连接
      • 4、on子句连接
      • 5、左、右、全外连接
  • 十一、子查询
    • 1、子查询当成数据表(更精确地说是当成视图)
    • 2、把子查询当成where条件中的值
      • 2.1 返回单行单列
      • 2.2 返回多行单列
      • 2.3 返回多行多列
  • 十二、集合运算
    • 1、union运算
    • 2、minus运算
    • 3、intersect运算

一、关系数据库基本概念和MySQL基本命令

1.1 数据库的概念和类型分类

严格来说,数据库(Database)仅仅只是用户存放数据的地方。当用户访问、操作数据库中的数据时,就需要数据库管理系统的帮助。数据库管理系统的全称Database Management System,简称DBMS。习惯上将数据库和数据库管理系统称为数据库。

DBMS是所有数据的知识库,它负责管理数据的存储、安全、一致性、并发、恢复和访问等操作。DBMS有一个数据字典(有时也称为系统表),用于存储它拥有的每个事务的相关信息,例如名字、结构、位置和类型,这种关于数据的数据称为元数据**。

在数据库的发展史中,按时间顺序主要体现了如下几种类型的数据库系统:

1、网状型数据库

2、层次型数据库

3、关系数据库

理论最成熟、应用最广泛的数据库,在大量数据的查找、排序操作上非常成熟且快速,并对数据库系统的并发隔离有非常完善的解决方案。对于关系数据库而言,最基本的数据存储单元就是数据表,因此可以简单地将数据库想象成大量数据表的集合(当然,数据库绝不是由数据表组成)。

数据表是存储数据的逻辑单元,可以将数据表想象成由行和列组成的表格,其中每一行称为一条记录,每一列称为一个字段。

4、面向对象数据库

面向语言催生的新型数据库,例如Oracle 11g等,还未大规模商用

1.2 MySQL数据库的命令

注意:MySQL默认以分号作为每条命令作为结束符,所以在每条语句结束后都应该输入一个英文分号(;)

1、MySQL数据库的一个实例(Sever Instance)可以包含多个数据库,MySQL查看当前实例下包含多少个数据库:

show databases;

2、用户需要创建新的数据库:

create database [IF NOT EXISTS] 数据库名;

3、删除指定数据库:

drop database 数据库名;

4、建立数据库后,如果想操作该数据库(例如为该数据建表,在该数据库中执行查询等操作),则需要进入该数据库。进入指定数据库可以使用以下命令:

use 数据库名;

5、进入指定数据库后,如果需要查询该数据库下包含多少个数据表,可以使用如下命令:

show tables;

6、查询指定数据表的表结构(查看该表有多少列,每列的数据类型等信息),则可以使用如下命令:

desc 表名;

上面MySQL的命令行客户端,依次执行了show databases;、create database if not exists abc;等,如果将多条MySQL命令写入一份SQL脚本文件里,然后将这份SQL脚本里的内容一次性复制到该窗口,将可以看到该命令行客户端一次性执行所有SQL命令的效果——这种一次性执行多条SQL命令的方式也被称为导入SQL脚本

7、MySQL数据库安装成功后,在其安装目录下有一个bin路径(我的为C:\Program Files\MySQL\MySQL Server 8.0\bin),在该路径下有一个mysql命令,该命令用于启动MySQL命令行客户端。执行mysql命令的语法:

mysql -p 密码 -u 用户名 -h 主机名 --default-character-set=utf8

1.3 MySQL数据库的存储机制

★MyISAM:早期默认的存储机制,对事务支持不够好。

★InnoDB:InnoDB提供食物安全存储机制。InnoDB通过建立行级锁来保证事务的完整性,并以Oracle风格的共享锁来处理Select语句。系统默认启动InnoDB存储机制,如果不想使用InnoDB表,可以使用skip-innodb选项。

InnoDB比MyISAM多了事务支持的功能,而事务支持是Java EE最重要的特性,因此通常推荐使用InnoDB存储机制。如果使用了5.0版本以上的MySQL数据库系统,通常无须指定数据表的存储机制,因为系统默认使用InnoDB存储机制。如果在建表时显示指定存储机制,可以在标准建表语句后添加以下任意一句:

★ENGINE=MyISAM:强制使用MyISAM存储机制。

★ENGINE=InnoDB:强制使用InnoDB存储机制。

二、SQL语句基础

SQL的全称是Structrued Query Language,也就是结构化查询语言。SQL是操作和检索关系数据库的标准语言,标准的SQL语句可用于操作任何关系数据库。

使用SQL语句,程序员与数据库管理员(DBA)可以完成如下任务:

★在数据库检索信息

★对数据库的信息进行更新

★改变数据库的结构

★更改数据库的安全设置

★增加和回收用户对数据库的、表的许可权限

一般程序员可以完成前3个任务,后两个任务由DBA来完成。

标准的SQL语句分为几种类型:

1、查询语句:主要由select关键字完成,查询语句是SQL语句中最复杂、功能最丰富的语句。

2、DML(Data Manipulation Language,数据操作语言)语句:主要由insert、updata和delect三个关键字组成。

3、DDL(Data Definition Language,数据定义语言)语句:组要由create、alter、drop和truncate四个关键字完成。

4、DCL(Data Control Language,数据控制语言)语句:主要由grant和revoke两个关键字完成。

5、事务控制语句:主要有commit、rollback和savepoint三个关键字完成。

SQL语句的关键字不区分大小写,DCL语句为数据库用户授权,回收指定的用户的权限,通常无须程序员操作。

在SQL命令中可能需要使用标识符,用于定义表名、列名等,标识符命名规则:

★必须以字母开头(注:C语言可以是下划线开头)

★标识符包含字母、数字和三个特殊字符(#_$)

★不要使用当前数据库系统的关键字、保留字,通常建议使用多个单词连缀而成,单词之间以_分隔

★同一个模式下的不同对象不应该同名,这里的模式指的是外模式。

三、DDL语句

DDL是操作数据库对象的语句,包括创建(crate)、删除(drop)、修改(alter)数据库对象。

最基本的数据库对象是数据表,数据表是存储数据的逻辑单元。但数据库绝不仅包括数据表,数据库里还包括如下几种常见的数据库对象:

对象名称 对应关键字 描述
table 表是存储数据的逻辑单元,以行和列的形式存在;列是字段,行是记录
数据字典 就是系统表,存放数据库相关信息的表。系统表里的数据通常由数据库系统维护,程序员不应该手动修改系统表及系统表里的数据,只可查看系统表里的数据
约束 constraint 执行数据校验的规则,用于保证数据完整性的规则
视图 view 一个或多个数据表里数据的逻辑显示。试图并不存储数据
索引 index 用于提高查找性能,相当于书的目录
函数 function 用于完成一次特定计算,具有一个返回值
存储过程 procedure 用于完成一次完整业务处理,没有返回值,但可通过传出参数将多个值传给调用环境
触发器 trigger 相当于一个事件监听器,当数据库发生特定事件后,触发器被触发,完成相应处理

因为存在上面几种数据库对象,所以在create后可以紧跟不同的关键字。例如建表使用create table,建索引create index,建试图create view...drop、alter用法类似。

3.1 创建表的语法

标准的建表语法格式:

create table [模式名.]表明
(
  #可以有多个列定义
  columnName1 datatype [default expr],
  ...
)

上面的圆括号多个列之间以英文逗号(,)隔开,最后一个定义不需要使用英文逗号,而是直接以括号结束。列定义由列名、列类型和可选的默认值组成。

例如下面的建表语句:

create table test
(
#整数类型通常用int
test_id int,
#小数点数
test_price decimal,
#普通长度文本,使用default指定默认值
test_name carchar(255) default ‘XXX‘,
#大文本类型
test_desc text,
#图片
test_img blob,
#时间
test_date datetime
);

MySQL可支持的列类型

列类型 说明
tinyint/smallint/mediumint/int(integer)/bigint 1字节/2字节/3字节/4字节/8字节整数,可分为有符号和无符号两种。这些整数类型区别仅仅只是表数范围不同
float/double 单精度/双精度浮点数类型
decimal(dec) 精确小数类型,相对于float/double不会产生精度丢失问题
date 日期类型,不能保存时间。把java.util.Date对象保存进date列时,时间部分将丢失
time 时间类型,不能保存日期。把java.util.Date对象保存进time列时,日期部分将丢失
datetime 日期、时间类型
timestamp 时间戳类型
year 年类型,仅仅保存时间的年份
char 定长字符串类型
varchar 可变长度字符串类型
binary 定长二进制字符串类型,它以二进制形式保存字符串
varbinary 可变长度的二进制字符串类型,它以二进制形式保存字符串
tinyblob/blob/mediumblob/longblob 1字节/2字节/3字节/4字节的二进制大对象,可用于存储图片、音乐等二进制数据,分别可存储:255B/64K/16MB/4GB的大小
tinytext/text/mediumtext/longtext 1字节/2字节/3字节/4字节的文本对象,可用于存储超长长度的字符串,分别可存储:255B/64K/16MB/4GB的大小的文本
enum(‘value1‘,‘value2‘...) 枚举类型,该列的值只能是enum后括号里多个值的其中一个
set(‘value1‘,‘value2‘...) 集合类型,该列的值可以是set后括号里多个值的其中几个

上面的建表语句只是创建了一个空表,该表里没有任何数据。如果使用子查询建表语句,则可以在建表的同时插入数据,子查询建表语句语法:

create table [模式名.]表名 [column[,column...]]
as sunquery;

上面语法新表的字段必须与子查询中字段列数量匹配,创建新表时的字段列表可以省略,如果省略了该字段列表,则新表的列名与选择结果完全相同。下面语句使用子查询来建表:

#创建hehe数据表,该数据表和user_inf完全相同,数据也完全相同
create table hehe
as
select *from user_inf;

3.2 修改表结构语法

修改表结构语法使用alter table,修改表结构包括增加列定义、修改列定义、删除列、重命名列等操作。

(1)增加列定义的语法如下:

    alter table 表名
    add
    (
    #可以有多个列定义
    column_name1 datatype [default expr],column_name2 datatype [default expr],...
    )

上面的列定义是追加到已有表的列定义后面,如果只是新增一列,则可以省略圆括号,仅在add后紧跟一个列定义即可。例如为数据表增加字段的SQL语句如下:

增加字段时:如果数据表已有数据记录,除非给新增的列指定默认值,否则新增的数据列不可指定非空约束,因为那些已有的记录在新增的列上肯定时空(实际上,修改表结构很容易失败,只要新增的约束与已有数据冲突,修改就会失败)。

(2)修改列定义的语法格式:

alter table 表名
modify column_name datatype [default expr] [first|afer col_name];

上面语法中first或者after col_name指定需要将目标修改到指定位置。如果数据表里已有数据记录,则修改列定义很容易失败,因为有可能修改的列定义规则与原有的数据记录不符合。如果修改数据列的默认值,则只会对以后插入的操作有作用,对以前的数据不会有任何影响。

(3)删除列的语法

alter table 表名
drop column_name;

(4)重命名数据表和完全该表列定义

//重命名数据表
alter table 表名 rename to 新表名;
//完全改变类定义
alter table 表名 change old_column_name new_column_name type [default expr] [first|after col_name];

3.3 删除表的语法

删除表的语法格式:

drop table 表名;

删除数据表的效果如下:

★表结构被删除,表对象不再存在。

★表里所有的数据也被删除。

★该表相关的索引、约束也被删除。

3.4 truncate表

对于大部分数据库而言,truncate被当作DDL处理,truncate被称为“截断”某个表。它的作用时删除该表里的全部数据,但保留表结构。相对于DML里delete命令而言,truncate速度要块很多。

truncate 表名;

四、数据库约束

约束时表上强制执行的数据校验规则,约束主要用于保证数据的完整性。除此之外,当表的数据存在相互依赖性时,可以保护相关数据据不被删除。

大部分数据库支持下面5中完整的约束:

★NOT NULL:非空约束,指定某列不能为空。

★UNIQUE:唯一约束,指定某列或几列组合不能重复。

★PRIMARY KEY:主键,指定该列的值可以唯一地标识该条记录。

★FOREIGN KEY:外键,指定该行记录从属于主表的一条记录,用于保证参照的完整性。

★CHECK:检查,指示一个布尔表达式,用于指定对应列的值必须满足该表达式。

注意:MySQL不支持CHECK约束,虽然MySQL的SQL语句也可以使用CHECK约束,但是这个CHECK约束不会产生任何作用。

根据约束对数据列的限制,约束分为下面两类:

1、单列约束:每个约束只约束一列

2、多行约束:每个约束可以约束多个数据列。

为数据表指定约束的两个时机:

1、建表的同时为相应的数据列指定约束。

2、建表后创建,以修改的方式来增加约束。

MySQL使用information_schema数据库里的TABLE_CONSTRAINTS表来保存该数据库的实例中的所有约束信息,用户可以通过查询TABLE_CONSTRAINTS表来获取该数据库的约束信息。

4.1 NOT NULL约束

非空约束用于确保指定列不允许为空,非空约束是比较特殊的约束,它只能作为列级约束使用,只能使用列级约束语法定义。

SQL中null不区分大小写,具有以下特征:

1、所有数据类型的值都可以是null,包括int,float,boolean等。

2、空字符不等于null,0也不等于null。

如果在建表时为指定列指定非空约束,只要在列后增加not null即可,建表语句如下:

create table hehe
(
    #建立非空约束
    hehe_id int not null,
    #MySQL的非空约束不能指定名字
    hehe_name varchar(255) default ‘xyz‘ not null,
    #下面列可以为空,默认就是可以为空
    hehe_gender varchar(255) null
);

除此之外通过alter table修改表时增加或删除非空约束,SQL命令如下:

#增加非空约束
alter table hehe modify hehe_gender varchar(2) not null;
#取消非空约束
alter table hehe modify hehe_name varchar(2) null;
#取消非空约束,并指定默认值
alter table hehe modify hehe_name varchar(255) default ‘abc‘ null;

4.2 UNIQUE约束

唯一约束用于保证指定列或指定列组合不允许出现重复值。虽然唯一约束的列不可以出现重复值,但可以出现多个null值(因为数据库中null不等于null)。

同一个表可以建立多个唯一约束,唯一约束也可以有多列组合而成。当为某列创建唯一约束时,MySQL会为该列相应地创建唯一索引。如果不给唯一索引取名,改唯一约束默认于列名相同。

唯一约束即可以使用列级约束语法建立,也可以使用表级语法建立。如果需要为多列建组合约束,或则要为唯一约束指定约束名,只能用表级约束语法。

1、列级语法建立唯一约束

当使用列级约束建立唯一约束,只是简单地在列定义后增减unique关键字即可。SQL语法如下:

#建表时创建唯一约束,使用列级约束语法建立约束
crate table unique_test
(
    #建立非空约束,意味者test_id不可以为null
    test_id int not null,
    #使用列级约束语法建立唯一约束
    test_name varchar(255) unique;
)

2、表级语法建立唯一约束

如果要为多列组合建立唯一约束,或者想自行指定约束名,则需要使用表级约束语法。语法格式如下:

[constrain 约束名] 约束定义

上面表级约束语法既可以放在create table语句中与列定义并列,也可以放在alter table语句中add添加关键字来添加约束。SQL语句如下:

上面建表语句为test_name,test_pass分别建立唯一约束,意味者这两列不能出现重复值。

为两列组合建立唯一约束,SQL语句

3、修改表结构时添加约束

例如:

#在修改表结构时使用add关键字添加唯一约束
alter table table_test1
add unique(test_name,test_pass);
#在修改表时使用modify关键字,为单列采用列级约束语法来增加唯一约束
alter table table_test1
modify test_name varvhar(255) unique;

4、删除约束

对于大部分数据库删除约束都是在alter table语句后使用"drop constraint 约束名"语法来完成,但是MySQL并不是使用这种方式,而是使用“drop index 约束名”的方式来删除约束。例如下面的SQL语句:

#删除table_test1表上的test_uk唯一约束
alter table table_test1 drop index test_uk;

4.3 PRIMARY KEY约束

主键约束相当于非空约束和唯一约束,即主键约束的列不允许出现重复值,也不允许出现null值;如果对多列组合建立主键约束,则多列里包含的每一列都不能为空,但要求这些列的组合不能重复。主键的列可以唯一地标识表中的一条记录。

建立主键约束时既可以使用表级约束也可以使用列级约束语法。如果需要对多个字段建立组合主键约束,则只能使用表级约束语法。使用表级约束建立约束时,可以为该约束指定约束名。但不管用户是否为该约束指定约束名,MySQL总是将所有主键约束命名为PRIMARY。

当创立主键约束结束时,MySQL在主键约束所在的列或列组合上建立唯一索引。同一个表只能创建一个主键约束

1、创建主键约束

列级语法建立主键约束

create table primary_table1
(
    #建立主键约束
    test_id int primary key,
    test_name varchar(255)
);

表级语法建立主键约束

create table primary_table2
(
    test_id int not null,
    test_name varchar(255),
    test_pass varchar(255),
    #指定主键约束名为test_pk,对大部分数据库有效,但对MySQL无效
    #MySQL数据库的主键约束名仍然是PRIMARY
    constraint test_pk primary key(test_id)
);

以列的组合形式创建主键时,只能使用表级约束语法

create table primary_table3
(
    test_name varchar(255),
    test_pass varchar(255),
    #以列的组合形式创建主键约束
    primary key(test_name,test_pass)
);

2、删除主键约束

#删除主键约束
alter table primary_table3
drop primary key;

3、增加主键约束

只是为单独的数据列增加主键约束,使用modify修改列定义来实现。SQL语句如下:

#使用列级语法建立主键约束
alter table primary_table3
modify test_name varchar(255) primary key;

为单独数据列或列组合创建主键约束,使用add来增加主键约束,SQL语法如下:

alter table primary_table3
add primary key(test_name,test_pass);

4、主键列支持自增长特性

大多数数据库都支持自增长的特性。指定自增长功能通常用于设置逻辑主键列——该列的值没有任何物理意义,仅仅用于标识每条记录。MySQL使用auto_increment来设置自增长,SQL语句如下:

create table primary_table4
(
    #建立主键约束,使用自增长
    test_id int auto_increment primary key,
    test_name varchar(255),
    test_pass varchar(255)
);

一旦制指定了某列具有自增长特性,则向该表插入记录时,可以不为该列指定值,该列的值由数据库系统自动生成。

4.4 FOREIGN KEY约束

外键约束主要用于保证一个或两个数据表之间的参照完整性,外键约束是构建一个表的两个字段或则两个表的两个字段之间的参照关系。外键约束确保了两个字段的参照关系:子(从)表外键列的值必须在主表被参照列的值范围之内,或者为空(也可以通过非空约束来约束外键列不允许为空)。

外键约束注意点:

★主表记录被从表记录参照时,主表记录不允许被删除,必须把从表里参照该该记录的所有的所有记录全部删除,才可以删除主表的该记录。或者删除主表记录时级联删除从表所有参照该记录的从表记录。

★从表外键参照的只能是主表主键列或唯一键列,这样才能保证从表记录准确定位到被参照的主表记录。同一个表可以拥有多个外键列。

★建立外键约束时,MySQL也会为该列建立索引。

★外键约束通常用于定义两个实体之间的一对多、一对一的关联关系。对于一对多的级联关系,通常在多的一端建立外键列。对于一对一的级联关系,则可以选择任意一方增加外键列,增加外键列的表称为从表,只要为外键列增加唯一约束就可以表示一对一的关联关系。

1、建立外键约束

采用列级约束语法建立外键约束直接使用references关键字,references指定参照哪个主表,以及参照主表的哪一列。SQL语句如下:(但是对于MySQL不会生效)

    #通常为了保证从表参照的主表存在,通常应该先建立主表
    create table teacher_table
    (
        #auto_increment代表数据库的自动编号策略,通常用于数据表的逻辑主列
        teacher_id int auto_increment,
        teacher_name varchar(255),
        primary key(teacher_id)#使用表级约束建立主键约束
    );

    #建立从表
    create table student_table
    (
        #为本表建立主键约束
        student_id int auto_increment prmary key,
        student_name varchar(255),
        #指定java_teacher参照teacher_table的teacher_id列
        java_teacher int references teacher_table(teacher_id)
    );

MySQL支持使用列级语法来建立外键约束,但是这种列级语法建立的外键约束不会生效,MySQL提供这种列级语法仅仅只是为了和标准SQL保持良好的兼容性。因此,如果要使MySQL外键约束生效,则应该使用表记语法:

    #通常为了保证从表参照的主表存在,通常应该先建立主表
    create table teacher_table1
    (
        #auto_increment代表数据库的自动编号策略,通常用于数据表的逻辑主列
        teacher_id int auto_increment,
        teacher_name varchar(255),
        primary key(teacher_id)#使用表级约束建立主键约束
    );

    #建立从表
    create table student_table1
    (
        #为本表建立主键约束
        student_id int auto_increment prmary key,
        student_name varchar(255),
        #指定java_teacher参照teacher_table的teacher_id列
        java_teacher int,
        foreign key(java_teacher) references teacher_table(teacher_id)
    );

使用表级约束语法可以为外键约束指定约束名,如果创建外键约束名没有指定约束名,则MySQL会为该外键约束命名为table_name_ibfk_n,其中table_name是从表的表名,而n是从1开始的整数。

如果需要显式创建外键约束名,可使用constraint来指定名字。SQL语句如下:

    #通常为了保证从表参照的主表存在,通常应该先建立主表
    create table teacher_table2
    (
        #auto_increment代表数据库的自动编号策略,通常用于数据表的逻辑主列
        teacher_id int auto_increment,
        teacher_name varchar(255),
        primary key(teacher_id)#使用表级约束建立主键约束
    );

    #建立从表
    create table student_table2
    (
        #为本表建立主键约束
        student_id int auto_increment prmary key,
        student_name varchar(255),
        java_teacher int,
        #使用表级约束建立外键约束,指定外键约束名为student_teacher_fk
        constraint student_teacher_fk foreign key(java_teacher) references teacher_table2(teacher_id)
    );

为多列组合建立外键约束,则必须使用表级约束语法,SQL语法如下:

    #通常为了保证从表参照的主表存在,通常应该先建立主表
    create table teacher_table3
    (
        teacher_id int auto_increment,
        teacher_name varchar(255),
        teacher_pass varchar(255),
        #以两列建立组合主键
        primary key(teacher_name,teacher_pass)
    );
    create sudent_table3
    (
        #为本表建立主键约束
        student_id int auto_increment primary key,
        student_name varchar(255),
        java_teacher_name varchar(255),
        java_teacher_pass varchar(255),
        使用表记约束建立外键约束,指定两列的联合外键
        foreign key(java_teacher_name,java_teacher_pass)
            references teacher_table3(teacher_name,teacher_pass)
    );

2、删除外键约束

#删除student_table3表上名为student_table3_ibfk_1外键约束
alter table student_table3
drop foreign key student_table3_ibfk_1;

3、增加外键约束

增加表记约束通常使用add foreign key命令。SQL语法如下:

    #修改student_table3数据表,增加外键
    add foreign key(java_teacher_name,java_teacher_pass)
        references teacher_table3(teacher_name,teacher_pass);

4、创建自关联

外键约束不仅可以参照其他表,而且可以参照自身,这种参照自身的情况通常被称为自关联。

下面的SQL语句用于建立自关联的外键约束。

    #使用表级约束语法建立外键约束,且直接参照自身
    create table foreign_table
    (
        foreign_id int auto_increment primary key,
        foreign_name varchar(255),
        #使用表的refer_id参照本身的foreign_id列
        refer_id int,
        foreign key(refer_id) references foreign_table(foreign_id)
    );

5、删除主表记录,从表记录随之删除

★建立外键约束后添加on delete cascade,删除主表记录时,把参照该主表记录的从表记录全部级联删除;

★建立外键约束后添加on delete set null,删除主表记录时,把参照该主表记录的从表记录的外键设为null;

    #通常为了保证从表参照的主表存在,通常应该先建立主表
    create table teacher_table4
    (
        #auto_increment代表数据库的自动编号策略,通常用于数据表的逻辑主列
        teacher_id int auto_increment,
        teacher_name varchar(255),
        primary key(teacher_id)#使用表级约束建立主键约束
    );

    #建立从表
    create table student_table4
    (
        #为本表建立主键约束
        student_id int auto_increment prmary key,
        student_name varchar(255),
        java_teacher int,
        #使用表级约束建立外键约束,指定外键约束名为student_teacher_fk
        constraint student_teacher_fk foreign key(java_teacher) references teacher_table4(teacher_id)
            on delete cascade
    );

4.5 CHECK约束

当前版本的MySQL支持建表时指定CHECK约束,但这个约束不会有任何作用。建立CHECK约束的语法很简单,只要在建表的列定义后增加check(逻辑表达式)即可,SQL语句如下:

create table check_table
(
    emp_id int auto_increment,
    emp_name varchar(255),
    emp_salary decimal,
    primary key(emp_id),
    #建立CHECK约束
    check(emp_slary>0)
);

虽然上面的语句创建了CHECK约束,CHECK约束要求emp_salary大于0,但这个要求实际并不会起作用。

五、索引

索引是存在模式(schema)中的一个数据对象,虽然索引总是从属于数据表,但它和数据表一样属于数据库。创建索引的唯一作用就是加速对表的查询,索引通过快速路径访问访问方法来快速定位数据,从而减少磁盘的I/O。

索引作为数据库对象,在数据字典中独立存放,但不能独立存在,必须属于某个表。

5.1 创建索引

创建索引有两种方式:

自动:当表上定义主键约束、唯一约束、外键约束时,系统会为该数据列自动创建对应的索引。

手动:用户可以通过create index...语句来创建索引。

通常为经常需要查询的数据列建立索引,可以在一列或多列上创建索引。创建索引的语法格式:

create index index_name
on table_name(column[,column]...);

下面的索引会提高对employees表基于last_name字段的查询速度

create index emp_last_name_idx
on employees(last_name);

也可以同时对多列建立索引,SQL语句格式:

#下面语句为employees的first_name和last_name两列同时建立索引
create index emp_last_name_idx2
on employees(last_name,first_name);

5.2 删除索引

自动:数据表被删除时,该表上的索引自动删除。

手动:用户可以通过drop index...语句来删除指定数据表上的指定索引。

MySQL中删除所有需要指定表,采用如下语法格式:

drop index 索引名 on 表名

如下语句删除了employee表上的emp_last_name_idx2

drop index emp_last_name_idx2 on employees

有些数据库删除索引时无须指定表名,因为它们要求创建索引时每个索引都有唯一的名字,所以须指定表名,例如Oracle就是采用的这种策略。但MySQL只要求同一个表内的索引不能同名,所以删除索引时必须指定表名。

索引的好处是可以加速查询。但索引也有两个坏处:

1、与书的目录相似,但数据表中的记录被添加、删除、修改时,数据库需要维护索引,因此有一定的系统开销。

2、存储索引信息需要一定的磁盘空间。

索引举例例如:

查看表格table_index的详细描述:

mysql> use test;
Database changed
mysql> desc table_index;
+-----------+--------------+------+-----+---------+-------+
| Field     | Type         | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+-------+
| test_id   | int(11)      | NO   |     | NULL    |       |
| test_uk   | varchar(255) | YES  | UNI | NULL    |       |
| test_name | varchar(255) | NO   | PRI | NULL    |       |
| test_pass | varchar(255) | YES  | MUL | NULL    |       |
| test_city | varchar(255) | YES  | MUL | NULL    |       |
+-----------+--------------+------+-----+---------+-------+
5 rows in set (0.00 sec)

六、视图

视图看上去很像一个数据表,但它并不是数据表,因为它并不能存储数据。视图只是一个或多个数据表的逻辑显示。使用视图有几个好处:

★可以限制对数据的访问

★可以使复杂的查询变得简单

★提供了数据的独立性

★提供了对相同数据的不同显示

6.1 创建视图

视图只是数据表中数据的逻辑显示——也就是一个查询结果,所以创建视图就是创建视图名和查询语句的关联。创建视图的语法:

create or replace view 视图名
as
subquery;

上面语法的含义是,如果视图不存在,则创建视图;如果指定视图名已经存在,则使用新视图替换原有视图。后面的subquery就是一个查询语句,这个查询可以非常复杂。

一旦视图创建成功后,使用视图与使用数据表就没有什么区别,但通常只是查询视图数据,不会修改视图里的数据,因为视图本身没有存储数据。

例如下面的SQL语句就创建了一个简单的视图:

create or replace view view_test
as
select teacher_name,teacher_pass from teacher_table;

通常不推荐直接改变视图的数据,因为视图并不存储数据,它只是相当于一条命名的查询语句而已。为了强制不允许改变视图的数据,MySQL允许在创建视图时使用with check option子句,使用该子句创建的视图不允许修改,例如:

create or replace view view_test
as
select teacher_name,teacher_pass from teacher_table
#指定不允许修改该视图的数据
with check option;

注意:大部分数据库采用with check option来强制不允许修改视图的数据,但Oracle采用with read only来强制不允许修改视图的数据。

6.2 删除视图的语句

drop view 视图名;

七、DML(Data Manipulation Language)语句语法

与DDL操作数据库对象不同的是,DML主要是操作数据表里的数据,使用DML可以完成如下三个任务:

★插入新数据

★修改已有数据

★删除不需要的数据

DML语句主要由insert into、update和delete from三个命令组成

7.1 insert into插入记录

先定义两个数据表:

insert into用于向指定数据表中插入记录。对于标准的SQL语句而言,每次只能插入一条记录。insert into语句的语法格式:

insert into table_name [(column [,column...])]
values(value [value...]);

执行插入操作时,表名后可以用括号列出所有需要插入列的列名,而values后用括号列出所有对应列需要插入的值。

如果省略了表名后的圆括号以及括号里的列名,默认为所有列都插入值,则需要为每一个列都指定一个值。如果既不想在表名后列出列名,又不想为所有列都指定值,则可以为那些无法确定值得列分配null。

向teacher_table2表插入两条记录:

外键约束的规则:外键列里的值必须是被参考列里已有的值,所有向从表里插入记录之前,通常应该向主表插入记录,否则从表记录的外键值只能为null。现在主表teacher_table2中已有2条记录,现在可以向从表student_table2中插入记录,SQL语句如下:

mysql> insert into student_table2
    -> values(null,‘张三‘,2);
Query OK, 1 row affected (0.13 sec)

mysql> select *from student_table2;
+------------+--------------+--------------+
| student_id | student_name | java_teacher |
+------------+--------------+--------------+
|          1 | 张三         |            2 |
+------------+--------------+--------------+
1 row in set (0.00 sec)

在一些特别的情况,可以使用带子查询的插入语句,带子查询的语句可以一次插入多条记录,SQL语句如此啊:

insert into student_table2(student_name)
#使用带子查询的值来插入
select teacher_name from teacher_table2;

带子查询的插入语句,只要求选择出来的数据列和插入目的表的数据列个数、数据类型匹配即可。

MySQL提供一种扩展语法,通过这种扩展语法可以一次插入多条记录。MySQL允许在values后使用多个括号包含多个记录,标识多条记录的多个括号之间以英文逗号(,)隔开。SQL语句如下:

insert into teacher_table2
values(null,‘Yeeku‘),(null,‘Sharfly‘);

7.2 update语句——修改表记录

update语句用于修改数据表的记录,每次可以修改多条记录,通过使用where子句限制修改哪些记录。where子句是一个条件表达式,该条件表达式类似于if语句,只有符合该条件的记录才会被修改。没有where子句则意味着where表达式总是为true,即该表的所有记录都会被修改。update语句的语法格式:

update table_name
set column1=value1[column2=value2]...
[WHERE condition];

例如将teacher_table2表的teacher_name列的值都改为孙悟空:

mysql> select *from teacher_table2;
+------------+--------------+
| teacher_id | teacher_name |
+------------+--------------+
|          1 | xyz          |
|          2 | abc          |
+------------+--------------+
2 rows in set (0.00 sec)

mysql> update teacher_table2
    -> set teacher_name=‘孙悟空‘;
Query OK, 2 rows affected (0.18 sec)
Rows matched: 2  Changed: 2  Warnings: 0

mysql> select *from teacher_table2;
+------------+--------------+
| teacher_id | teacher_name |
+------------+--------------+
|          1 | 孙悟空       |
|          2 | 孙悟空       |
+------------+--------------+
2 rows in set (0.00 sec)

通过where来指定修改特定的记录,SQL语句如下:

mysql> update teacher_table2
    -> set teacher_name=‘猪八戒‘
    -> where teacher_id>1;
Query OK, 1 row affected (0.16 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select *from teacher_table2;
+------------+--------------+
| teacher_id | teacher_name |
+------------+--------------+
|          1 | 孙悟空       |
|          2 | 猪八戒       |
+------------+--------------+
2 rows in set (0.07 sec)

7.3 delete from删除语句

delete from不需要指定删除指定的列名,因为总是整行删除。可以一次删除多行,删除哪些行采用where子句限定,只删除满足where条件的记录。

delete from语句的语法格式:

delete from table_name
[WHERE condition];

如下SQL语句将student_table2表中的记录全部删除:

delete from student_table2;

使用where条件限定只删除指定记录,SQL语句如下:

delete from teacher_table2
where teacher_id>2;

当主表记录被从表参照时,主表记录不能被删除,只有先将从表中参照主表记录的所有记录被全部删除后,才可以删除主表记录,还有一种情况,定义外键约束时定义主表和从表记录之间的级联删除关系on delete cascade,或者使用on delete set null用于指定主表记录被删除时,从表参考该记录的从表记录把外键值设定为null。

八、单表查询

8.1 基本语法说明

select语句不仅可以执行单表查询,而且也可以执行多表查询,还可以进行子查询,select语句用于从一个或多个数据表中选出特定行、特定列的交集。select语句最简单的功能如下图所示:

单表查询的select语句的语法格式:

select column1,column...
from 数据源
[where condition]

数据源:表、视图等。

select后的列表是确定选出的哪些列,如果需要选出所有列,可使用星号(*)代表所有列。

where条件用于确定哪些行被选出,没有where条件,则会默认选择出所有行。

例如选择存储teacher_table2表中的所有行和所有列的数据:

select * from teacher_table2;

我们先导入一个select.sql文件的SQL语句:

drop database if exists select_test;
create database select_test;
use select_test;
# 为了保证从表参照的主表存在,通常应该先建主表。
create table teacher_table
(
	# auto_increment:实际上代表所有数据库的自动编号策略,通常用作数据表的逻辑主键。
	teacher_id int auto_increment,
	teacher_name varchar(255),
	primary key(teacher_id)
);
create table student_table
(
	# 为本表建立主键约束
	student_id int auto_increment primary key,
	student_name varchar(255),
	# 指定java_teacher参照到teacher_table的teacher_id列
	java_teacher int,
	foreign key(java_teacher) references teacher_table(teacher_id)
);
insert into teacher_table
values
(null, ‘Yeeku‘);
insert into teacher_table
values
(null, ‘Leegang‘);
insert into teacher_table
values
(null, ‘Martine‘);
insert into student_table
values
(null, ‘张三‘, 1);
insert into student_table
values
(null, ‘张三‘, 1);
insert into student_table
values
(null, ‘李四‘, 1);
insert into student_table
values
(null, ‘王五‘, 2);
insert into student_table
values
(null, ‘_王五‘, 2);

insert into student_table
values
(null, null, 2);
insert into student_table
values
(null, ‘赵六‘, null);

8.2 where语句选出特定行

where条件语句选出student_table表中的java_teacher值等于2的student_name列的值:

8.3 在select语句中使用算术运算符(+、-、*、/)

使用算数表达式的规则:

1、对数值型整数列、变量、常量可以使用算术运算符(+、-、、/)创建表达式;

2、对日期型数据列、变量、常量可以部分使用算术运算符(+、-、、/)创建表达式,两个日期之间可以进行进行减法运算,日期和数值之间可以进行加、减运算;

3、运算符不仅可以在列和常量、变量之间进行运算,也可以在两列之间进行运算。

select后不仅可以是数据列,也可以是表达式,还可以是变量、常量等,例如下面的语句也是正确的:

8.4 concat()函数进行字符串连接运算

SQL语句如下;

#选择出teacher_table和‘xx‘字符串进行连接
select concat(teacher_name,‘xx‘)
from teacher_table;

8.5 算数表达式现null值

对于MySQL而言,在算术表达式中使用null,将会导致整个算数表达式的返回值为null;

8.6 为数据列或表达式取别名

别名紧跟数据列,中间以空格隔开,或者使用关键字as隔开

如果列别名中使用了特殊字符例如空格,或者需要强制大小写敏感,都可以通过为别名添加双引号来实现。SQL语句如下:

select teacher_id+5 as "My id"
from teacher_table;

如果选择多列,并为多列取别名,列与列之间用逗号隔开,但列和列别名之间以空格隔开或as隔开

8.6 为表名取别名

select teacher_id+5 as "My id",teacher_name 老师名
from teacher_table t;

8.7 在select、where中都不出现列名

where后面的表达式总是为true,所以teacher_table的每条记录都会被选择出来——但SQL没有选择任何列,仅仅选择了三个常量,所以SQL会把各个常量单独当成一列,teacher_table有多少条记录,该常量就出现多少次。

实际上指定数据表没有任何意义,所以MYSQL提供了一种扩展语法,允许在select语句后没有from子句,即可写成如下形式:

select 5+4;#我的当前版本不支持这种扩展

上面的语句不是一个标准的SQL语句,例如Oracle就提供了一个名为dual的虚表(新版的MYSQL也支持这种用法),他没有任何意义,仅仅相当于from后面的占位符。如果选择常量,则可以使用如下语句:

8.8 distinct去重

select默认会把所以符合条件的记录全部选择出来,即使两行的记录完全相同。如果想去除重复行,则可以使用distinct关键字从查询结果中清除重复行。比较下面两行SQL语句执行结果:

8.9 where子句中的比较运算符

SQL的比较运算符不仅可以比较数值之间的大小,也可以比较字符串、日期之间之间的大小。

注意:SQL判断相等的比较运算符是单等号,判断不相等的运算符是<>;SQL的赋值运算符不是等号,而是冒号等号(:=)。

SQL还支持几种特殊的比较运算符

运算符 含义
expr1 between expr2 and expr3 要求expr1>=expr2并且expr2<=expr3
expr1 in(expr2,expr3...) 要求expr1等于后面括号任意一个表达式的值
like 字符串匹配,like后面的字符串支持通配符
is null 要求指定值等于null

★使用expr1 between expr2 and expr3必须保证expr2小于expr3,否则不会选出记录。除此之外between expr2 and expr3中的两个值不仅可以是常量,也可以是变量或者列名也行。例如SQL语句选出java_teacher小于等于2,student_id大于等于2的记录:

mysql> select *from student_table
    -> where 2 between student_id and java_teacher;

★in括号里的值既可以是常量、变量、表达式

mysql> select *from student_table
    -> where 2 in(student_id,java_teacher);
+------------+--------------+--------------+
| student_id | student_name | java_teacher |
+------------+--------------+--------------+
|          2 | 张三         |            1 |
|          4 | 王五         |            2 |
|          5 | _王五        |            2 |
|          6 | NULL         |            2 |
+------------+--------------+--------------+
4 rows in set (0.00 sec)

mysql>)

★like主要用于模糊查询。

在SQL中可以使用两个通配符:下划线(_)和百分号(%),下划线可以代表任意一个字符,百分号可以代表任意多个字符。

例如下main语句选出学生姓名以“张”开头的学生:

mysql> select *from student_table
    -> where student_name like "张%";
+------------+--------------+--------------+
| student_id | student_name | java_teacher |
+------------+--------------+--------------+
|          1 | 张三         |            1 |
|          2 | 张三         |            1 |
+------------+--------------+--------------+
2 rows in set (0.00 sec)

在某些情况下,查询条件里需要使用下划线和百分号,不希望SQL把下划线和百分号当成通配符使用,这就需要转义字符,MySQL使用反斜线(\)作为转义字符,例如下面的SQL语句:

mysql> select *from student_table
    -> where student_name like "\_%";
+------------+--------------+--------------+
| student_id | student_name | java_teacher |
+------------+--------------+--------------+
|          5 | _王五        |            2 |
+------------+--------------+--------------+
1 row in set (0.00 sec)

标准的SQL语句没有提供反斜线的转义字符,而是使用escape关键字进行显式转义。例如:

mysql> select *from student_table
    -> where student_name like "\_%" escape ‘\‘;

★is null用于判断某些值是否为空,判断是否为空不要使用=null来判断,因为SQL中null=null返回null。

mysql> select *from student_table
    -> where student_name is null;
+------------+--------------+--------------+
| student_id | student_name | java_teacher |
+------------+--------------+--------------+
|          6 | NULL         |            2 |
+------------+--------------+--------------+
1 row in set (0.00 sec)

8.10 where子句中的条件组合

SQL中提供的三个关系运算符and\or\not.例如下面的语句选出学生名为2个字符且student_id大于3的所有记录。

mysql> select *from student_table
    -> where student_name like ‘__‘ and student_id>3;
+------------+--------------+--------------+
| student_id | student_name | java_teacher |
+------------+--------------+--------------+
|          4 | 王五         |            2 |
|          7 | 赵六         |         NULL |
+------------+--------------+--------------+
2 rows in set (0.00 sec)

8.11 比较运算符、逻辑运算符的优先级

运算符 优先级(优先级小的优先)
圆括号() 0
所有比较运算符 1
not 2
and 3
or 4

8.12 执行查询后的结果排序

执行查询后的查询结果默认按插入顺序排列;如果要查询结果按某列值得大小进行排序,则可以使用order by子句。order by子句得语法格式如下:

order by column_name1[desc],column_name2...

进行排序时默认按照升序排序,如果强制按照降序排序,则需要在类后使用desc关键字(与之对应得是asc关键字,用不用该关键字得效果一样,因为默认按照升序排序)。

上面语法排序时可采用列名、列序号和列别名。

例如SQL语句按java_teacher列得升序得排列:

如果按照多列排序,则每列得asc、desc必须单独设定。如果指定了多个排序列,则第一个是首要排序列,只有当第一列出现多个相同值时,第二个排序列才会起作用。

九、数据库函数

根据函数对多行数据得处理方式,函数被分为单行函数和多行函数。单行函数对每行单独计算,每行得到一个计算结果返回给用户;多行函数对多行输入值整体计算,最后只得到一个结果。单行函数和多行函数得示意图如下:

执行函数得语法:

function_name(arg1,arg2...)

多行函数也称为聚集函数、分组函数,主要用于完成一些统计功能,大部分数据库中基本相同。但不同数据库得单行函数差别很大。

9.1 单行函数

MySQL中单行函数具有如下特点:

★单行函数得参数可以时变量、常量或数据列。

★单行函数会对每行起作用,每行(可能包含多个参数)返回一个结果。

★使用单行函数可以改变数据得类型。单行函数支持嵌套使用,即内参函数的返回值是外层函数的参数。

单行函数分类:

下面通过例子介绍MySQL单行函数的用法:

(1)char_length()返回字符串长度:

mysql> select *from teacher_table;
+------------+--------------+
| teacher_id | teacher_name |
+------------+--------------+
|          1 | Yeeku        |
|          2 | Leegang      |
|          3 | Martine      |
+------------+--------------+
3 rows in set (0.00 sec)

mysql> select char_length(teacher_name)
    -> from teacher_table;
+---------------------------+
| char_length(teacher_name) |
+---------------------------+
|                         5 |
|                         7 |
|                         7 |
+---------------------------+

(2)sin()计算sin值

mysql> select sin(teacher_id)
    -> from teacher_table;
+--------------------+
| sin(teacher_id)    |
+--------------------+
| 0.8414709848078965 |
| 0.9092974268256817 |
| 0.1411200080598672 |
+--------------------+
3 rows in set (0.00 sec)

(4)日期时间函数

#为指定日期添加一定时间
#在这种用法下interval是关键字,需要一个数值,还需要一个单位
mysql> select DATE_ADD(‘1998-01-02‘,interval 2 MONTH);
+-----------------------------------------+
| DATE_ADD(‘1998-01-02‘,interval 2 MONTH) |
+-----------------------------------------+
| 1998-03-02                              |
+-----------------------------------------+
1 row in set (0.00 sec)
mysql> select CURDATE()#获取当前日期
    -> ;
+------------+
| CURDATE()  |
+------------+
| 2020-04-10 |
+------------+
1 row in set (0.00 sec)

mysql> select curtime();#获取当前时间
+-----------+
| curtime() |
+-----------+
| 22:48:59  |
+-----------+
1 row in set (0.00 sec)

mysql>

(5)加密函数

mysql> select MD5(‘testing‘);
+----------------------------------+
| MD5(‘testing‘)                   |
+----------------------------------+
| ae2b1fca515949e5d54fb22b8ed95575 |
+----------------------------------+
1 row in set (0.00 sec)

(6)处理null函数

ifnull(expr1,expr2):如果expr1为null,则返回expr2,否则返回expr1.

nullif(expr1,expr2):如果expr1和expr2相等,则返回null,否则返回expr1.

if(expr1,expr2,expr3):有点类似于?:三目运算符,如果expr1为true,不等于0,且不等于null,则返回expr2,否则返回expr3.

isnull(expr1):判断expr1是否为空,如果为空则返回true,否则返回false。

#如果student_name列为null,则返回没有名字
select ifnull(student_name,‘没有名字‘);
#如果student_name等于‘张三‘,则返回null
select nullif(student_name,‘张三‘);

(7)流程控制函数case函数

第一个用法语法格式:

case value
when compare_value1 then result1
when compare_value2 then result2
...
else result
end

case函数用value依次与后面的compare_value1、compare_value2...依次进行比较,如果value和指定的compare_value1相等,则返回result1,否则与后面的compare_value比较,都没有匹配的情况,则返回result。

case函数的第一个用法的语法格式:

case
when condition1 then result1
when condition2 then result2
...
else result
end

condition1、condition2都返回一个boolean值得条件表达式,因此这种用法更加灵活:

通常不推荐使用特定函数库得函数,因为这将导致程序代码与特定数据库耦合;如果把该程序移植到其他数据库系统上,可能需要打开源程序,重新修改SQL语句。

9.2 分组和组函数

组函数就是多行函数,组函数将一组记录作为整体计算,每组记录返回一个结果。常用组函数由5个:

1、avg([distinct|all]expr):计算expr的平均值,expr可以是变量、常量或数据列,但类型必须是数值型。distinct去重;all和不用效果一样,表名需要计算重复值

2、count({|[distinct|all]expr}):计算多行expr总条数,expr可以是变量、常量或数据列,数据类型可以是任意类型。用星号()表示用该表内的记录行数;distinct表示不计算重复值。

3、max(expr):计算多行expr的最大值,其中expr可以是变量、常量或数据列,数据类型可以是任意类型。

4、min(expr):计算多行expr的最小值,其中expr可以是变量、常量或数据列,数据类型可以是任意类型。

5、sum([distinct|all]expr):计算expr的总和,expr可以是变量、常量或数据列,但类型必须是数值型。distinct去重;all和不用效果一样,表名需要计算重复值。

#计算student_table表内的记录条数
select count(*)
from student_table;
#计算java_teacher列共有躲闪个值
select count(distinct java_teacher)
from student_table;

#统计studet_id的总和
select sum(student_id)
from student_table;
#计算的结果是20*记录的函数
select sum(20)
from student_table;

#选出student_table的student_id的最大值
select max(student_id)
from student_table;

#选出student_table的student_id的最小值
select min(student_id)
from student_table;

#使用count统计时,null不会被计算在内
select count(student_name)
from student_table;

注意事项:

1、对于出现null的列,可以用ifnull函数来处理

select avg(ifnull(java_teacher,0))
from student_table;

2、ditinct和*不能同时使用

#将出现错误
count(distinct *)
from student_table;

3、默认情况下,函数会把所有记录当作一组,为了对记录显式分组,可以在select后面使用group by子句,后面可以跟一个或多个列名,表名查询结果根据一列或多列进行分组——当一列或多列组合的值完全相同时,系统会把这些记录当成一组。SQL语句如下:

如果对多列进行分组,要求多列的值完全相等才会被当成一组

mysql> select count(*)
    -> from student_table
    -> group by java_teacher,student_name;

4、having过滤组

十、多表连接查询

10.1 SQL 92连接查询

较早的SQL规范支持几种多表连接查询:

★等值连接

★非等值连接

★外连接

★广义笛卡尔积

SQL 92的多表连接语法比较简洁,这种语法把多个数据表都放在from之后,多个表之间以逗号隔开;连接条件放在where之后,与查询条件之间用and逻辑运算符连接。如果连接条件要求两列值相等,则称为等值连接,否则称为非等值连接;如果没有任何连接条件,则称为广义笛卡尔积。

1、多表连接语法格式

SQL多表连接连接查询的语法格式:

select column1,column2...
from table1,table2...
[where join_condition]

多表连接查询可能出现两个或多个数据列具有相同的列名,则需要在这些同列名之间使用表名前缀或表别名前缀,避免系统混淆。

2、等值连接

如下查询出所有学生的资料以及对于的老师姓名:

实际上,多表查询的过程可以理解一个嵌套循环,这个嵌套循环的伪码:

//遍历teacher_table表中的每条记录
for t in teacher_table
{
    //遍历student_table表的每条记录
    for s in student_table
    {
    //当满足条件时,输出两个表连接后的结果:
    if(s.java_teacher=t.teacher_id)
        output s+t
    }
}

3、非等值连接

举例:

select s.*,teacher_name
from student_table as s,teacher_table as t
where s.java_teacher>t.teacher_id;

相当于上面的伪码if语句改成if(s.java_teacher>t.teacher_id)

4、广义笛卡尔积

理解上面的伪码之后,就可以轻松理解多表连接查询的运行机制。如果求广义笛卡尔积,则where后没有任何连接条件,相当于没有上面的if语句,广义笛卡尔积的结果就会有n×m条记录。

5、其它用法

如果还需要记录进行过滤,则将过滤条件和连接条件使用and连接起来,SQL语句如下:

虽然SQL 92不支持左外连接、右外连接,但有必要了解。SQL 92的外连接是在连接条件的类名后增加括号包起来的外连接符(+或*,不同数据库有一定区别),当外连接符出现在左边时称为左外部连接,出现在右边称为右外部连接。

SQL语句如下:

select s.*,t.teacher_name
from student_table as s,teacher_table as t
#右连接
where s.java_teacher=t.teacher_id(*);

外连接就是在外连接符所在的表中增加一个“万能行”,这行记录的所有数据都为null,而且该行可以与另一个表中所有不满足条件的记录进行匹配,通过这种方式可以把另一个表中所有记录选出,不管这些记录是否满足连接条件。

除此之外,还有一种自连接。如果同一个表中的不同记录之间存在主、外键约束关联,例如员工、经理同在一个表里,则需要自连接查询。

下面的SQL语句建立一个自关联的数据表,并向表中插入4条数据:

如果需要查询该表中的所有员工名以及每个员工的经理名,则必须使用自连接查询。所谓自连接就是把一个表当成两个表来使用,就需要为一个表起两个别名,而且查询中用的所有数据列都要加表别名前缀,因为两个表的数据列完全一样。

例如下面的程序:

mysql> select emp.emp_id,emp.emp_name as 员工名,mgr.emp_name as 经理名
    -> from emp_table as emp,emp_table as mgr
    -> where emp.manager_id=mgr.emp_id;
+--------+--------+--------+
| emp_id | 员工名 | 经理名 |
+--------+--------+--------+
|      2 | 孙悟空 | 唐僧   |
|      3 | 猪八戒 | 唐僧   |
|      4 | 沙僧   | 唐僧   |
+--------+--------+--------+
3 rows in set (0.00 sec)

上述过程图示为:

10.2 SQL 99的连接查询

SQL 99连接查询的可读性更强——查询用的多个数据表显式使用xxx join连接,而不是直接依次排列在from之后,from后只需要放一个数据表;连接条件不再放在where之后,而是提供专门的连接条件子句。

1、交叉连接(cross join)

交叉连接效果就是SQL 92中的广义笛卡尔积,所以交叉连接无须任何连接条件。SQL语句:

2、自然连接(natural join)

自然连接以两个表中的同名列作为连接条件;如果两个表中没有同名列,则自然连接和交叉连接效果完全一样——因为没有连接条件。SQL语句如下:

mysql> select * from student_table;
+------------+--------------+--------------+
| student_id | student_name | java_teacher |
+------------+--------------+--------------+
|          1 | 张三         |            1 |
|          2 | 张三         |            1 |
|          3 | 李四         |            1 |
|          4 | 王五         |            2 |
|          5 | _王五        |            2 |
|          6 | NULL         |            2 |
|          7 | 赵六         |         NULL |
+------------+--------------+--------------+
7 rows in set (0.00 sec)

mysql> select *from teacher_table;
+------------+--------------+
| teacher_id | teacher_name |
+------------+--------------+
|          1 | Yeeku        |
|          2 | Leegang      |
|          3 | Martine      |
+------------+--------------+
3 rows in set (0.00 sec)

mysql> select s.*,teacher_name
    -> from student_table s
    -> natural join teacher_table t;
+------------+--------------+--------------+--------------+
| student_id | student_name | java_teacher | teacher_name |
+------------+--------------+--------------+--------------+
|          1 | 张三         |            1 | Yeeku        |
|          1 | 张三         |            1 | Leegang      |
|          1 | 张三         |            1 | Martine      |
|          2 | 张三         |            1 | Yeeku        |
|          2 | 张三         |            1 | Leegang      |
|          2 | 张三         |            1 | Martine      |
|          3 | 李四         |            1 | Yeeku        |
|          3 | 李四         |            1 | Leegang      |
|          3 | 李四         |            1 | Martine      |
|          4 | 王五         |            2 | Yeeku        |
|          4 | 王五         |            2 | Leegang      |
|          4 | 王五         |            2 | Martine      |
|          5 | _王五        |            2 | Yeeku        |
|          5 | _王五        |            2 | Leegang      |
|          5 | _王五        |            2 | Martine      |
|          6 | NULL         |            2 | Yeeku        |
|          6 | NULL         |            2 | Leegang      |
|          6 | NULL         |            2 | Martine      |
|          7 | 赵六         |         NULL | Yeeku        |
|          7 | 赵六         |         NULL | Leegang      |
|          7 | 赵六         |         NULL | Martine      |
+------------+--------------+--------------+--------------+
21 rows in set (0.00 sec)

3、using子句连接

using子句可以指定一列或多列,用于显式指定两个表中的同名列作为连接条件。假设两个表中有超过一列的同名列,如果使用nature join,则会把所有同名列当成连接条件;使用using子句,就可以显式使用哪些同名列作为来连接条件。SQL语句如下:

mysql> select s.*,teacher_name
    -> from student_table as s
    -> join teacher_table as t
    -> using(teacher_id);
ERROR 1054 (42S22): Unknown column ‘teacher_id‘ in ‘from clause‘

上面语句将出现一个错误,因为student_table表中并不存在名为teacher_id的列。也就是说使用using子句来指定连接条件,则两个表中必须有同名列,否则将出现错误。

4、on子句连接

SQL 99语法的连接条件放在on子句中指定,而且每个on子句只能指定一个连接条件。这就意味着:如果要进行N表连接,则需要N-1个join..on对。

SQL语句如下:

select s.*,teacher_name
from student_table s
join teacher_table t
on s.java_teacher=t.teacher_id;

使用SQL 99的on子句连接可以完全替代SQL 92的等值连接、非等值连接,广义笛卡尔积(on true),只需要设定好on字句后的连接条件即可。

5、左、右、全外连接

这三种连接分别使用left[outer] join、right[outer] join、full[outer] join,这三种外连接的连接条件一样通过on子句来指定,既可以是等值连接,也可以是非等值连接。

下面使用右外连接,连接条件是等值连接。

mysql> select s.*,teacher_name
    -> from student_table s
    -> right join teacher_table t
    -> on s.java_teacher=t.teacher_id;

下面使用左外部外连接,连接条件是等值连接。

比较左外连接和右外连接可以看出,SQL 99外连接与SQL 92外连接恰恰相反,SQL 99左外连接会把左边表中的所有不满足条件的记录全部列出;SQL 99右外连接会把右边表中的所有不满足条件的记录全部列出。

全外部连接会把两个表中所有不满足的记录全部列出:

mysql> select s.*,teacher_name
    -> from student_table s
    -> full join teacher_table t
    -> on s.java_teacher = t.teacher_id;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘full join teacher_table t
on s.java_teacher = t.teacher_id‘ at line 3
mysql>

目前MySQL不支持全外连接。

十一、子查询

子查询指的是再在查询语句中嵌套另一个查询,子查询可以支持多层嵌套。对于一个普通的查询语句而言,子查询可以出现在两个位置:

★出现在from语句后当成数据表,这种用法也称为行内视图,因为子查询就是一个临时的视图。

★出现在where条件后作为过滤条件。

使用子查询需要注意的事项:

(1)子查询使用圆括号括起来。

(2)把子查询当成数据表(出现在from之后),可以为该子查询起别名,尤其是作为前缀来来限定数据列,必须给子查询起别名。

(3)把子查询当成过滤条件时,将子查询放在比较运算符的右边,这样可以增加查询的可读性。

(4)把子查询当成过滤条件时,单行子查询使用单行运算符,多行查询使用多行运算符。

1、子查询当成数据表(更精确地说是当成视图)

子查询1当成数据表完全把子查询当成数据表来用,只是把之前的表名当成子查询(也可以为子查询起别名):

mysql> select *
    -> from(select*from student_table) t
    -> where t.java_teacher>1;
+------------+--------------+--------------+
| student_id | student_name | java_teacher |
+------------+--------------+--------------+
|          4 | 王五         |            2 |
|          5 | _王五        |            2 |
|          6 | NULL         |            2 |
+------------+--------------+--------------+
3 rows in set (0.12 sec)

上面的SQL语句理解成在执行查询时创建了一个临时视图,该视图名为t,所以创建这种临时视图也称为行内视图。

2、把子查询当成where条件中的值

2.1 返回单行单列

如果子查询返回单行单列值,则被当成一个标量值使用,也可以使用单行记录比较运算符。

2.2 返回多行单列

如果子查询返回多个值,则需要使用in、any、all等关键字,此时可以把子查询返回的多个值当成一个值列表。SQL语句:

any、all可以与>、<、>=、<=、<>、=等运算符结合使用,与any结合使用分别代表大于、小于、大于等于、小于等于、不等于、等于其中任意一个值;与all结合使用分别表示大于、小于、大于等于、小于等于、不等于、等于全部值。可以看出=any的作用与in的作用相同。如下SQL语句:

mysql> select *
    -> from student_table
    -> where student_id =
    -> any(select teacher_id
    -> from teacher_table);

<ANY只要小于列表中的最大值,>ANY只要大于值列表的最小值。<ALL要求小于列表中的最小值,>ALL要求小于列表中的最大值。

2.3 返回多行多列

此时必须要求where子句中应该有对应的数据列,并使用圆括号将多个数据列组合起来。SQL语句如下:

mysql> select *
    -> from student_table
    -> where (student_id,student_name)
    -> =any(select teacher_id,teacher_name
    -> from teacher_table);

十二、集合运算

还有一种查询对两个结果集进行集合运算,这两个结果集必须满足如下条件

★两个结果集所包含的数据列的数量必须相等。

★两个结果集所包含的数据列的数据类型必须一致。

1、union运算

union语句的语法格式如下:

select 语句 union select 语句

2、minus运算

minus运算的语法格式:

select 语句 minus select 语句

假如从所有学生记录中"减去"与老师ID相同、姓名相同的记录,则可以进行如下minus运算:

select student_id,student_name from student_table
minus
select teacher_id,teacher_name from teacher_table;

不过MySQL并不支持使用minus运算符,因此只能通过子查询来"曲线"实现minus运算:

mysql> select student_id,student_name from student_table
    -> where(student_id,student_name)
    -> not in (select teacher_id,teacher_name from teacher_table);
+------------+--------------+
| student_id | student_name |
+------------+--------------+
|          1 | 张三         |
|          2 | 张三         |
|          3 | 李四         |
|          4 | 王五         |
|          5 | _王五        |
|          6 | NULL         |
|          7 | 赵六         |
+------------+--------------+
7 rows in set (0.15 sec)

3、intersect运算

intersect运算的语法格式:

select 语句 intersect select 语句

不管MySQL也不支持叉运算,只能通过子查询来曲线实现:

多表连接查询实现:

mysql> select student_id,student_name from student_table
    -> join teacher_table
    -> on(student_id=teacher_id and student_name=teacher_name);
Empty set (0.00 sec)

如果进行intersect运算的两个select子句都包括了where条件,那么将intersect运算改成多表连接查询后还需要将两个where条件进行and运算。假如intersect运算的SQL语句为:

select student_id,student_name from student_table where student_id<4
intersect
select teacher_id,teacher_name from teacher_table where teacher_name likes ‘李%‘;

上面语句改成:

select student_id,student_name from student_table
join teacher_table
on(student_id=teacher_id and student_name=teacher_name)
where student_id<4 and teacher_name like ‘李%‘;

原文地址:https://www.cnblogs.com/weststar/p/12652359.html

时间: 2024-09-29 05:00:44

10.3 SQL语法的相关文章

LINQ To SQL 语法及实例大全

LINQ to SQL语句(1)之Where Where操作 适用场景:实现过滤,查询等功能. 说明:与SQL命令中的Where作用相似,都是起到范围限定也就是过滤作用的,而判断条件就是它后面所接的子句. Where操作包括3种形式,分别为简单形式.关系条件形式.First()形式.下面分别用实例举例下: 1.简单形式: 例如:使用where筛选在伦敦的客户 var q = from c in db.Customers where c.City == "London" select c

Hadoop Hive sql语法详解

Hive 是基于Hadoop 构建的一套数据仓库分析系统,它提供了丰富的SQL查询方式来分析存储在Hadoop 分布式文件系统中的数据,可以将结构化的数据文件映射为一张数据库表,并提供完整的SQL查询功能,可以将SQL语句转换为MapReduce任务进行运行,通过自己的SQL 去查询分析需要的内容,这套SQL 简称Hive SQL,使不熟悉mapreduce 的用户很方便的利用SQL 语言查询,汇总,分析数据.而mapreduce开发人员可以把己写的mapper 和reducer 作为插件来支持

SQLite的SQL语法

SQLite库能够解析大部分标准SQL语言.但它也省去了一些特性而且增加了一些自己的新特性.这篇文档就是试图描写叙述那些SQLite支持/不支持的SQL语法的.查看keyword列表. 例如以下语法表格中,纯文本用蓝色粗体显示.非终极符号为斜体红色.作为语法一部分的运算符用黑色Roman字体表示. 这篇文档仅仅是对SQLite实现的SQL语法的综述,有所忽略.想要得到更具体的信息,參考源码和语法文件“parse.y”. SQLite运行例如以下的语法: ALTER TABLE ANALYZE A

SQLite的 SQL语法总结

SQLite库可以解析大部分标准SQL语言.但它也省去了一些特性并且加入了一些自己的新特性.这篇文档就是试图描述那些SQLite支持/不支持的SQL语法的.查看关键字列表. 如下语法表格中,纯文本用蓝色粗体显示.非终极符号为斜体红色.作为语法一部分的运算符用黑色Roman字体表示. 这篇文档只是对SQLite实现的SQL语法的综述,有所忽略.想要得到更详细的信息,参考源代码和语法文件“parse.y”. SQLite执行如下的语法: ALTER TABLE ANALYZE ATTACH DATA

ORACLE分页查询SQL语法——最高效的分页

--1:无ORDER BY排序的写法.(效率最高)--(经过测试,此方法成本最低,只嵌套一层,速度最快!即使查询的数据量再大,也几乎不受影响,速度依然!) SELECT * FROM (SELECT ROWNUM AS rowno, t.* FROM emp t WHERE hire_date BETWEEN TO_DATE ('20060501', 'yyyymmdd') AND TO_DATE ('20060731', 'yyyymmdd') AND ROWNUM <= 20) table_

SQL语法整理

SQL是Structured Query Language的缩写,中文全名为结构化查询语言,是一种用于数据存储,查询,更新和管理的关系数据库系统. SQL语法 创建表 create table tablename (filedname1 filedtype1(长度),filedname2 filedtype2(长度),...) 创建视图 create view viewname as select statement 添加数据记录 insert into tablename (filed1,fi

[Android新手区] SQLite 操作详解--SQL语法

该文章完全摘自转自:北大青鸟[Android新手区] SQLite 操作详解--SQL语法  :http://home.bdqn.cn/thread-49363-1-1.html SQLite库可以解析大部分标准SQL语言.但它也省去了一些特性并且加入了一些自己的新特性.这篇文档就是试图描述那些SQLite支持/不支持的SQL语法的.查看关键字列表. 如下语法表格中,纯文本用蓝色粗体显示.非终极符号为斜体红色.作为语法一部分的运算符用黑色Roman字体表示. 这篇文档只是对SQLite实现的SQ

SQL语法考核

--继上一篇MySQL的开发总结之后,适当的练习还是很有必要的-- SQL语法多变,不敢保证唯一,也不敢保证全对,如果错误欢迎指出,即刻修改. 一.现有表结构如下图 TABLENAME:afinfo Id name age birth sex memo 1 徐洪国 37 1979-03-23 男 高中 2 王芳 26 1988-02-06 女 本科 3 李达康 24 1990-04-02 男 硕士 4 侯亮平 30 1984-09-12 女 博士 5 徐夫子 27 1987-12-30 男 大专

Linq语法详细(三种方式:linq、Lambda、SQL语法)

三种方式:linq.Lambda.SQL语法 1.简单的linq语法 //1 var ss = from r in db.Am_recProScheme select r; //2 var ss1 = db.Am_recProScheme; //3 string sssql = "select * from Am_recProScheme"; 2.带where的查询 //1 var ss = from r in db.Am_recProScheme where r.rpId >