数据库(三)—— 关系数据库标准语言SQL(Mysql)

一、SQL概述

1、SQL的特点

1.1 综合统一

满足以下操作要求:

① 定义和修改、删除关系模式,定义和删除视图,插入数据,建立数据库;

② 对数据库中的数据进行查询和更新;

③ 数据库重构和维护;

④ 数据库安全性、完整性以及事务控制;

⑤ 嵌入式SQL和动态SQL定义。

1.2 高度非过程化

        用户无须了解存储路径,存取路径的选择以及SQL的操作过程由系统自动完成,这不仅减轻了用户负担,而且提高了数据独立性。

1.3 面向集合的操作方式

        SQL采用集合操作方式,不仅操作对象、查找结果可以是元组的集合,而且插入、删除、更新操作的对象也可以是元组的集合。

1.4 以同一种语法结构提供多种使用方式

        SQL既是独立的语言,又是嵌入式语言。用户可以在终端键盘上直接键入SQL命令对数据库进行操作,也能够嵌入到高级程序语言(JAVA、C、C++)中,供程序员设计程序时使用。

1.5 语言简洁,易学易用

SQL功能 使用动词
数据查询 SELECT
数据定义 CREATE、ALTER、DROP
数据操作 INSERT、UPDATE、DELETE
数据控制

GRANT、REVOKE

2、SQL的基本概念

        支持SQL的关系数据库同样支持关系数据库的三级模式结构。外模式包含若干视图和部分基本表,数据库模式包含若干基本表,内模式包含若干存储文件。

        基本表和视图一样,都是关系。基本表是本身独立存在的表,一个关系就对应一个基本表,一个或多个基本表对应一个存储文件。一个表可以带若干索引,索引也存放在存储文件中。存储文件的逻辑结构组成了关系数据库的内模式。 

        视图是从一个或几个基本表导出的表,它本身不独立存储在数据库中,视图只是一个虚拟表,它只是在概念上与基本相同。

        下面以Mysql为例,以Oracle为例可以参考:Oracle使用(二)—— 一些常用的SQL命令和基础知识(包含权限、序列、视图、索引、完整性约束、事务等) 

二、数据定义

1、数据库模式定义

数据库模式定义包含数据库的创建、选择、修改、删除、查看等操作。

⑴ 创建数据库

在Mysql中,可以使用create database或create schema创建数据库,其语法格式如下:

CREATE {DATABASE|SCHEMA}[IF NOT EXISTS] db_name
[DEFAULT] CHARACTER SET [=] charset_name|[DEFAULT]COLLATE[=]collation_name

        此语法中,“[]”标示其内容为可选项,“|”用于用于分隔花括号中的选择项,表示可任选一项,“db_name”用于标识具体的数据库名称,关键字“DEFAULT”用于指定默认值,关键字“CHARACTER SET”用于指定数据库字符集,关键字“COLLATE”用于指定字符 集的校对规则,关键字“IF NOT EXISTS”用于在创建数据库前进行判断,只有该数据库不存在时才执行创建操作,这样可避免出现数据库已经存在而再创建的错误。

示例如下:

mysql> create database if not exists learn_mysql;

⑵ 查看数据库

        在Mysql中,查看数据库的语法格式如下:

SHOW {DATABASES|SCHEMAS} [LIKE 'pattern'|WHERE expr]

         此语法中,可选项“LIKE”用于匹配指定的数据库名称,可选项“WHERE”从句用于指定数据库查询范围的条件,此语句只能查看用户权限范围内所能查看到的所有数据库名称。

示例如下:

mysql> show databases;

⑶ 选择数据库

        在Mysql中,使用USE语句可以实现从一个数据库切换到另一个数据库,只有使用USE命令指定某个数据库为当前数据库之后,才能对该数据库及其存储的数据对象进行各种操作。

示例如下:

use learn_mysql;

 ⑷ 修改数据库

 修改已有数据库learn_mysql的默认字符集和校对规则,其语法如下:

ALTER {DATABASE|SCHEMA} [db_name] alter_specification ...

 示例如下:

alter database learn_mysql default character set utf8 default collate utf8_general_ci;

 ⑸ 删除数据库

其语法如下:

DROP {DATABASE|SCHEMA} [IF EXISTS] db_name

此语法中的关键字“IF EXISTS”用来判断是否存在要删除的数据库。另外,需要注意的是使用此语句进行删除时,会删除当前数据库下的所有表以及其中的数据,使用该语句时要谨慎。

示例如下:

drop database if exists learn_mysql;

2、表定义

        只有成功创建数据库之后,才能在数据库中创建数据表,数据表是关系数据库中最重要、最基本的数据对象,也是数据存储的基本单位。

        数据表被定义为字段的集合,创建数据表的过程,实质上就是定义每个字段的过程,同时也是实施数据完整性约束的过程。其中,确定表中每个字段的数据类型是创建表的重要步骤,而字段的数据类型则是定义该字段所能存储的数据值的类型。

⑴ 创建表

创建表的语法如下:

CREATE [TEMPORARY] TABLE user
(
	字段名1 数据类型 [列级完整性约束条件][默认值],
	字段名2 数据类型 [列级完整性约束条件][默认值],
	......
	[表级完整性约束条件]
)[ENGINE=引擎类型]

创建一个表的实例如下:

create table user
(
	oid int not null auto_increment comment '自增主键',
	username varchar(50) not null comment '用户名',
	pwd varchar(100) not null comment '用户密码',
	sex char(2) not null default '男' comment '用户性别',
	address varchar(200) comment '用户住址',
  phone varchar(20) comment '电话',
  primary key (oid)
)ENGINE=INNODB;

 创建表相关注意事项如下:

① 临时表与持久表

        使用关键字"TEMPORARY"创建的表为临时表,不用该关键字创建的表为持久表。临时表只对创建它的用户可见,当断开与该数据库的连接时,Mysql会自动删除它们。

② 数据类型

        数据库中每个列都应有适当的数据类型,用于限制或允许该列中存储的数据。数据类型可帮助正确的排序数据,并在优化磁盘使用方法起着重要的作用。

        在Mysql中,主要的数据类型包括数值类型、日期和时间类型、字符串类型、空间数据类型等。

③ 关键字AUTO_INCREMENT

        使用关键字"AUTO_INCREMENT"可以为表中数据类型为整型的列设置自增属性,从而能实现当插入NULL或数字0到该列时,该列的值会自动设置为"该列最大值加1",AUTO_INCREMENT的顺序是从数字1开始的,同时每个表只能有一个AUTO_INCREMENT列,并且它必须被索引,其次该列的值是可以被覆盖的,当为该列指定一个尚未使用的唯一的值时,这个值将会替代系统自动生成的值,并且后续的增量将基于该值开始自增。

④ 指定默认值

        默认值是指向表插入数据时,如果没有明确给出某个列所对应的值,则数据库会为此列指定一个值,它使用关键字"DEFAULT"。如果没有指定默认值,则Mysql会自动分配一个,如果可以取NULL,则默认值为NULL,如果该列被定义为NOT NULL则默认值取决于该列的数据类型(对于非AUTO_INCREMENT列的数字类型,默认值是0,表中第一个TIMESTAMP列,默认值是当前的日期和时间)。

⑤ NULL值

        NULL值是指没有值或缺值,它是Mysql中没有指定DEFAULT列以及NOT NULL列的默认值。

⑥ 主键

        主键主要是通过PRIMARY KEY关键字来指定。主键值必须唯一,而且主键一定要为NOT NULL。

⑵ 更新表

        ALTER TABLE语句用来更改原有的表结构。

① ADD[COLUMN] 子句

        该子句可以用来向表中添加新列,且其可同时增加多个列。示例如下:

alter table user
add column nation char(2) not null default '汉' comment '民族' after phone;

         上例中,关键字"AFTER"在原表phone列后新增了一列nation,也可以通过关键字"FIRST" 将新列作为原表的第1列使用,若不指定这两个关键字,新列会自动添加到表的最后一列。类似的方法,可以使用ADDPRIMARY KEY子句、ADDFOREIGN KEY子句、ADD INDEX子句为原表添加一个主键、外键和索引等。

② CHANGE[COLOUMN]子句

        该子句可同时修改表中指定列的名称和数据类型,且可以同时放入多个该子句,彼此用逗号分隔。示例如下:

alter table user
change column nation nation_info varchar(5) null comment '民族信息';

 注意:如果将列原有的数据类型更换为另一种数据类型,可能会丢失该列原有的数据;如果试图改变的数据类型与原有的数据类型不兼容,SQL命令不会执行,且系统提示错误;而在类型兼容的情况下,该列的数据可能会被截断。

③ ALTER[COLUMN]子句

        如果需要修改或删除表中指定列的默认值,可以使用该语句。示例如下:

alter table user
alter column sex set default '女';

④ MODIFY[COLUMN]子句

        与CHANGE子句不同,该子句只能修改指定列的数据类型,而不会干涉它的列名。另外,该子句还可以通过关键字"AFTER"和"FIRST"来重新指定列在表中的位置。示例如下:

alter table user
modify column nation_info char(2) first;

⑤ DROP[COLUMN]子句

        该子句可以删除表中的列。示例如下:

alter table user
drop column nation_info;

注意:一旦列被删除,存储在该列中的内容都会被删除。类似的,也可以通过DROP PRIMARY KEY子句、DROP FOREIGN KEY子句、DROP INDEX子句来删除表中的主键、外键和索引等。

⑥ RENAME[TO]子句 

        该子句可以为表重新赋予一个表名。示例如下:

alter table user
rename to tb_user;

⑶ 重命名表

        除了使用ALTER TABLE语句来更改表名外,还可以使用RENAME TABLE语句来更改表的名字,并可同时命名多个表。语法格式如下:

RENAME TABLE table1 to newName1 [,table2 to newName2]...

示例如下:

rename table dept to tb_dept,emp to tb_emp;

⑷ 查看表

 ① 查看表名

        查看表使用SHOW TABLES来显示指定数据库中存放的所有表名,其语法格式如下:

SHOW [FULL] TABLES [{FROM|IN}db_name] [LIKE 'pattern'|WHERE expr]

        示例如下:

show tables from demo like 'tb%';

② 查看表结构

        使用SHOW COUMUNS语句来显示指定数据表的结构,其语法格式如下:

SHOW [FULL] COLUMNS {FROM|IN} tb_name [{FROM|IN} db_name] [LIKE 'pattern'|WHERE expr]

        示例如下:

show columns from tb_user;

⑸ 删除表

        删除表通过DROP TABLE语句来实现,语法格式如下:

DROP [TEMPORARY] TABLE [IF EXISTS] tb_name[,tb_name]... [RESTRICT|CASCADE]

         示例如下:

drop table tb_user;

 3、索引定义

        所谓索引,就是数据库根据表中的一列或若干列按照一定顺序建立的列值与记录行之间的对应关系表,因而索引实际上是一张描述索引列的列值与原表中记录行之间一一对应关系的有序表。在列上创建了索引之后,查找数据时可以直接根据该列上的索引找到对应记录行的位置,从而快速的查找到数据。

        如果没有索引,数据库会通过全表扫描的方式逐个读取指定表中的数据记录来进行访问,如此查询的效率自然是非常低的。所以,索引是提高数据文件访问效率的有效方法,尽管索引可以加快数据查询的速度,但过多的使用索引也会增加系统的开销,因为索引也存在着一些弊端。如下:

① 索引是以文件的形式存在的,数据库会将一个表的所有索引保存在同一个索引文件中,索引文件需要占用磁盘空间,如果有大量的索引,索引文件可能会比数据文件更快地达到最大的文件尺寸。特别是当一个大表上创建了多种组合索引时,索引文件会膨胀的很快;

② 在更新索引列上的数据时,索引会被自动更新,以确保索引树与表中的内容保持一致。如果表中的索引很多,则更新表的时间也会变长。

索引在逻辑上通常包含如下几类:

① 普通索引(INDEX)

        最基本的索引,没有任何限制,创建时通常使用关键字INDEX或KEY(INDEX和KEY是同义词)。

② 唯一性索引(UNIQUE)

        它和普通索引的区别在于,此索引列中所有的值都只能出现一次,必须是唯一的。

③ 主键(PRIMARY KEY)

        主键是一种唯一性索引。创建主键时,必须指定PRIMARY KEY关键字,且不能有空值,每个表只能有一个主键。

 

        在实际使用中,索引通常被创建为单列索引和组合索引。单列索引就是一个索引只包含原表中的一个列;而组合索引也称复合索引或多列索引,它是原表中多个列共同组成的索引。一个表可以有多个单列索引,但这些索引不能是组合索引。

⑴ 索引的创建

① 使用CREATE INDEX语句创建索引

        使用该该语句可以在一个已有的表上创建索引,但该语句不能创建主键。其语法格式如下:

/*使用CREATE INDEX语句创建索引的语法格式*/
CREATE [UNIQUE] INDEX index_name ON tb_name(index_column_name)
/*index_column_name的语法格式如下*/
column_name[(length)][ASC|DESC]

         可选项"UNIQUE"关键字用于指定创建唯一性索引;"index_name"用于指定索引名,一个表可以创建多个索引,但每个索引在该表中的名称必须是唯一的。

        "column_name"指定要创建索引的列名,可选项"length"用于指定使用列的前length个字符来创建索引,使用列的一部分创建索引有利于减小索引文件的大小,节省磁盘空间。

        示例如下:

/*使用CREATE INDEX语句创建索引示例*/
create index index_user on user(username(3));
/*查看上个示例创建的索引*/
show index from user;

② 使用CREATE TABLE语句创建索引 

        索引可以在创建表的时候一起创建,在使用CRATE TABLE语句定义列选项的时候,可以直接在某个列定义后面添加关键字"PRIMARY KEY"的方式来创建主键,如果是多列索引,就需要在语句最后加上一个PRIMARY KEY(column_name,...)的子句来实现,INDEX、UNIQUE [INDEX]、FOREIGN KEY等索引也是通过子句来添加的。

        语法项如下:

/*建表时创建索引的语法项*/
[CONSTRAINT [symbol]] PRIMARY KEY (index_column_name,...)/*用于创建表的时候创建该表的主键*/
{INDEX|KEY} [index_name] (index_column_name,...)/*用于创建表的时候创建该表的索引*/
[CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] [index_name](index_column_name,...)/*用于创建表的时候创建该表的唯一索引*/

        示例如下:

/*建表时创建联合主键索引和普通索引*/
create table user
(
	oid int not null auto_increment comment '自增主键',
	username varchar(50) not null comment '用户名',
	pwd varchar(100) not null comment '用户密码',
	sex char(2) not null default '男' comment '用户性别',
	address varchar(200) comment '用户住址',
  phone varchar(20) comment '电话',
  primary key (oid,username),
  index index_user(phone)
)ENGINE=INNODB;

③ 使用ALTER TABLE语句创建索引 

        在使用该语句修改表结构的同时,可以向已有的表中添加索引。语法项只需要多加一个ADD关键字即可,示例如下:

alter table user
add unique unique_index_user(phone)

⑵ 索引的查看

        其语法格式如下:

SHOW {INDEX|KEYS} {FROM|IN} tb_name [{FROM|IN} db_name] [WHERE expr]

        示例如下:

show index from user;

⑶ 索引的删除

① 使用DROP INDEX语句删除索引

        其语法格式如下:

DROP INDEX index_name on tb_name

         示例如下:

drop index index_user on user

 ② 使用ALTER TABLE语句删除索引

        DROP PRIMARY KEY子句用于删除表中的主键(自增主键不可删除,要首先更改列定义为非自增才能删除),DROP INDEX子句用于删除各种类型的索引,DROP FOREIGN KEY子句用于删除外键。可以同时删除多种类型的索引,用逗号隔开。

示例如下:

alter table user
drop index unique_index_user

三、数据更新 

1、插入数据

        INSERT语句有三种语法形式,分别是INSERT...VALUES语句、INSERT...SET语句、INSERT...SELECT语句。

① INSERT...VALUES语句插入单行或多行数据

        其语法格式如下:

INSERT [INTO] tb_name [(column_name,...)]
{VALUES|VALUE}({expr|DEFAULT},...),(...),...

        示例如下:

insert into user(oid,username,pwd,sex,address,phone)
values(null,'zhangsan','zhangsan','男','地球','110');

② INSERT...SET语句插入部分列值数据

        其语法格式如下:

INSERT [INTO] tb_name SET column_name={expr|DEFAULT},...

        示例如下:

insert into user set username='wang1',pwd='wang1'; 

 ③ INSERT...SELECT语句插入子查询数据

        其语法格式如下:

INSERT [INTO] tb_name [(column_name,...)]
SELECT ...

        在此语法中,SELECT子句用于快速地从一个或多个表中取出数据,并将这些数据作为行数据插入到另一个表中,SELECT子句返回的是一个查询到的结果集,INSERT语句将这个结果集插入到指定表中,其中结果集每行数据的字段数、字段的数据类型必须与被操作的表完全一致。示例如下:

insert into user(username,pwd)
select 'Tom1','Tom1' from dual
union
select 'Tom2','Tom2' from dual

 2、更新数据

        其语法格式如下:

UPDATE tb_name SET column_name1={expr1|DEFAULT}[,column_name2={expr2|DEFAULT}]..
[WHERE where_condition]
[ORDER BY ...]
[LIMIT row_count]

        在上面的语法中,WHERE子句用于限定表中要修改的行,如果不指定此子句,则会修改所有的行;可选项LIMIT用于限定被修改的行数。示例如下:

update user set username='alex' where oid = 1

3、删除数据

        其语法格式如下:

DELETE FROM tb_name [WHERE where_condition] [ORDER BY ...] [LIMIT row_count]

         在上面的语法中,如果省略WHERE子句,则表示删除表中所有的行;LIMIT子句用于告知服务器在控制命令被返回到客户端前被删除的行的最大值。示例如下:

delete from user where username like 'Tom%'

四、数据查询

1、select语句 

        该语句的执行过程是从数据库选取匹配的行和列,并将这些数据组织成一个结果集,然后以一张临时表的形式返回。常用的语法格式如下:

SELECT
	[ALL|DISTINCT|DISTINCTROW]
	select_expr [,select_expr ...]
	FROM table_references
	[WHERE where_condition]
	[GROUP BY {column_name|expr|position} [ASC|DESC],... [WITH ROLLUP]]
	[HAVING where_condition]
	[ORDER BY {column_name|expr|position} [ASC|DESC],...]
	[LIMIT {[offset,] row_count|row_count OFFSET offset}]

        在上面的语法结构中,SELECT子句用于指定输出的字段;FROM子句用于指定数据的来源;WHERE用于指定数据的选择条件;GROUP BY用于对检索到的数据进行分组;HAVING子句用于指定组的选择条件;ORDER BY子句用于对查询的结果进行排序。在这些子句中,只有SELECT子句和FROM子句是必需的,其他子句都是可选的。

        在SELECT语句中,三个关键字ALL、DISTINCT、DISTINCTROW 为可选项,用于指定是否返回 结果集中的重复行,若没有指定,默认为ALL,即SELECT操作中所有匹配的行,包括可能重复的行。而选择另外两个时会消除重复的行。

2、列的选择与指定

⑴ 选择指定的列

        选择多个查询列时,列名之间要用逗号进行分隔,如果要查询所有列,可以使用*通配符来进行替代。示例如下:

/*查询user表中的所有记录*/
select * from user
/*只查询user表中的用户名和密码*/	
select username,pwd from user

⑵ 定义并使用列的别名

        在SELECT子句后面可以添加AS子句来指定结果集中列的别名。示例如下:

/*查询user表中的用户名并指定别名*/
select username as uname from user

⑶ 替换查询结果集中的数据

        当希望得到对某些列的查询分析结果,而不是原始数据时,可以使用CASE表达式。示例如下:

/*查询user表中的sex列并使用CASE表达式将列值为'男'的值替换成man*/
select (
	case 
		when sex = '男' 
		then 'man' 
		else sex 
	end ) as sex from user

⑷  聚合函数

        聚合函数通常是数据库系统中的内置函数,常用于对一组值进行计算,然后返回单个的值。它通常与GROUP BY一起使用,如果SELECT语句中有一个GROUP BY子句,则这个聚合函数对所有行起作用;如果没有,则只产生一行作为结果。另外,除COUNT函数外,聚合函数都会忽略空值。

MYSQL中常用的聚合函数表
函数名 说明
COUNT 求组中项数,返回INT类型整数
MAX 求最大值
MIN 求最小值
SUM 返回表达式中所有值的和
AVG 求组中值的平均值
GROUP_CONCAT 返回由属于一组的列值连接组合而成的结果

示例如下:

/*统计user表中的总记录数*/
select count(1) from user
/*通过sex进行分组,并统计男、女性别的记录各有多少*/
select count(1) from user group by sex
/*查询user表oid自增到的最大值是多少*/
select max(oid) from user
/*将表中的所有用户名按oid进行排序拼接成一个字符串,并用逗号分隔(默认就是逗号)*/
select GROUP_CONCAT(username order by oid separator ',') from user

 下面的连接查询将使用Oracle数据库中的两张表来进行演示,其表结构和数据如下:

-- ----------------------------
-- Table structure for dept
-- ----------------------------
DROP TABLE IF EXISTS `dept`;
CREATE TABLE `dept` (
  `DEPTNO` int(11) NOT NULL,
  `DNAME` varchar(255) DEFAULT NULL,
  `LOC` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`DEPTNO`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of dept
-- ----------------------------
INSERT INTO `dept` VALUES ('10', 'ACCOUNTING', 'NEW YORK');
INSERT INTO `dept` VALUES ('20', 'RESEARCH', 'DALLAS');
INSERT INTO `dept` VALUES ('30', 'SALES', 'CHICAGO');
INSERT INTO `dept` VALUES ('40', 'OPERATIONS', 'BOSTON');
-- ----------------------------
-- Table structure for emp
-- ----------------------------
DROP TABLE IF EXISTS `emp`;
CREATE TABLE `emp` (
  `EMPNO` int(11) NOT NULL,
  `ENAME` varchar(255) DEFAULT NULL,
  `JOB` varchar(255) DEFAULT NULL,
  `MGR` int(11) DEFAULT NULL,
  `HIREDATE` date DEFAULT NULL,
  `SAL` double DEFAULT NULL,
  `COMM` double DEFAULT NULL,
  `DEPTNO` int(11) DEFAULT NULL,
  PRIMARY KEY (`EMPNO`),
  KEY `fk_dept` (`DEPTNO`),
  CONSTRAINT `emp_ibfk_1` FOREIGN KEY (`DEPTNO`) REFERENCES `dept` (`DEPTNO`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of emp
-- ----------------------------
INSERT INTO `emp` VALUES ('7369', 'SMITH', 'CLERK', '7902', '1980-12-17', '800', null, '20');
INSERT INTO `emp` VALUES ('7499', 'ALLEN', 'SALESMAN', '7698', '1981-02-20', '1600', '300', '30');
INSERT INTO `emp` VALUES ('7521', 'WARD', 'SALESMAN', '7698', '1981-02-22', '1250', '500', '30');
INSERT INTO `emp` VALUES ('7566', 'JONES', 'MANAGER', '7839', '1981-04-02', '2975', null, '20');
INSERT INTO `emp` VALUES ('7654', 'MARTIN', 'SALESMAN', '7698', '1981-09-28', '1250', '1400', '30');
INSERT INTO `emp` VALUES ('7698', 'BLAKE', 'MANAGER', '7839', '1981-05-01', '2850', null, '30');
INSERT INTO `emp` VALUES ('7782', 'CLARK', 'MANAGER', '7839', '1981-06-09', '2450', null, '10');
INSERT INTO `emp` VALUES ('7788', 'SCOTT', 'ANALYST', '7566', '1987-04-19', '3000', null, '20');
INSERT INTO `emp` VALUES ('7839', 'KING', 'PRESIDENT', null, '1981-11-17', '5000', null, '10');
INSERT INTO `emp` VALUES ('7844', 'TURNER', 'SALESMAN', '7698', '1981-09-08', '1500', '0', '30');
INSERT INTO `emp` VALUES ('7876', 'ADAMS', 'CLERK', '7788', '1987-05-23', '1100', null, '20');
INSERT INTO `emp` VALUES ('7900', 'JAMES', 'CLERK', '7698', '1981-12-03', '950', null, '30');
INSERT INTO `emp` VALUES ('7902', 'FORD', 'ANALYST', '7566', '1981-12-03', '3000', null, '20');
INSERT INTO `emp` VALUES ('7934', 'MILLER', 'CLERK', '7782', '1982-01-23', '1300', null, '10');

 3、from子句与多表连接查询

        通过在FROM子句中指定多个表时,SELECT操作会使用连接运算将不同表中需要查询的数据组合到一个结果集中,并同样以一个临时表的形式返回,其连接方式主要包括交叉连接、内连接、外连接。

⑴ 交叉连接

        交叉连接,又称迪卡尔积。它通过在FROM子句中使用CROSS JOIN来连接两张表,从而实现一张表的每一行与另一张表的每一行的迪卡尔乘积。在使用,也可以省略关键字CROSS JOIN,直接使用逗号进行分隔。示例如下:

/*交叉连接查询dept和emp*/
select * from dept cross join emp
select * from dept,emp

⑵ 内连接

        内边接是通过在查询中设置连接条件的方式,来移除查询结果集中某些数据行之后的交叉连接。具体而言,就是利用条件判断表达式中的比较运算符来组合两张表中的记录,其目的是为了消除交叉连接中的某些数据行。内连接使用INNER JOIN关键字,可以省略INNER,直接使用JOIN关键字。示例如下:

/*对交叉连接进行筛选变成内连接*/
select * from dept d cross join emp e on d.deptno = e.deptno
/*查询出job为"MANAGER"的员工信息和部门编号*/
select e.*,d.deptno from emp e join dept d on e.deptno=d.deptno where job='MANAGER'

        下面是进行其他连接测试添加的更改表结构和数据的SQL语句:

/*向dept中添加列(平均工资)设置10、20、30号部门的平均工资并提交*/
alter table dept add (avgsal double);
update dept set avgsal=3000 where deptno = 10;
update dept set avgsal=2000 where deptno = 20;
update dept set avgsal=1500 where deptno = 30;
commit;
/*向emp中添加一条没有部门的员工信息记录并提交*/
insert into emp(empno,ename,job,mgr,hiredate,sal,comm,deptno) values(8888,'ZHANG','ENGINEER',7788,sysdate(),3000,2000,null);
commit;

① 内连接的等值连接 

        在ON子句的连接条件中使用运算符“=”进行相等性测试的连接就是等值连接。示例如下:

select * from emp e join dept d on e.sal = d.avgsal

② 内连接的非等值连接

        在ON子句的连接条件中使用除运算符“=”之外的其他比较运算符进行不相等性测试的连接就是非等值连接。示例如下:

select * from emp e join dept d on e.sal > d.avgsal

③ 内连接中的自连接

        一个表与它自身进行连接,这种方式被称为自连接。示例如下:

select * from emp e1 join emp e2 on e1.empno = e2.mgr

⑶ 外连接

        外连接是将连接的两张表分为基表和参考表,然后再以基表为依据返回满足和不满足条件的记录、其中,外连接可以在表中没有匹配记录的情况下仍然返回记录。外连接分为左外连接、右外连接,示例如下:

/*左外连接:员工8888没有部门,只保留左表的悬浮元组,其他属性为null*/
select * from emp e left join dept d on e.deptno = d.deptno 
/*右外连接:40号部门没有人,只保留右表的悬浮元组,其他属性为null*/
select * from emp e right join dept d on e.deptno = d.deptno 

4、where子句与条件查询

        下面是常用的运算符及作用:

数据库(三)—— 关系数据库标准语言SQL(Mysql)_第1张图片

⑴ 比较运算

        除了“<=>”运算符,其他比较运算符返回逻辑值“真”或“假”,当表达式的值有一个为空或都为空时,则返回UNKNOWN;对于运算符“<=>”,当两个表达式彼此相等或都等于空值时,比较的结果值为TRUE,若其中有一个空值或都是非空却不相等时,则为FALSE,不会出现值为UNKNOWN的情况。示例如下:

/*查询emp表中工资大于等于3000的员工*/
select * from emp where sal >= 3000;
/*查询emp表中资金为空的员工*/
select * from emp where comm <=> NULL

⑵ 判定范围

① BETWEEN AND

        需要返回某一个数据值是否位于两个给定的值之间时,可以使用between...and来指定范围条件,指定的第一个值必须小于第二个值,因为between...and实质是“大于等于第一个值,并且小于等于第二个值”的简写形式,等价于比较运算符(>=...<=)。示例如下:

/*使用BETWEEN AND在emp表中查询工资在2000到3000之间的员工信息*/
select * from emp where sal between 2000 and 3000

② IN 

        测试一个数据值是否匹配一组目标值中的一个,该关键字可以用来指定列表搜索条件。示例如下:

/*在emp表中使用in关键字查询职务为"PRESIDENT"、"MANAGER"、"ANALYST"中任意一种的员工信息*/
select * from emp where job in('PRESIDENT','MANAGER','ANALYST');

⑶ 判定空值

        空值(NULL)从技术上来说就是未知的、不确定的值,但空值与空字符串不同,空值是不存在的值,而空字符串是长度为0的字符串。IS NULL判定是否为空,为空则返回TRUE,否则返回FALSE,而NOT  IS NULL正好与IS NULL相反。示例如下:

/*查询emp表中comm为null的员工*/
select * from emp where comm is null

⑷ 子查询

        在MYSQL中有四类子查询,分别是表子查询,返回的结果是一个表;行子查询,返回的结果集是一行数据;列子查询,返回的结果集是多行的一列数据;标量子查询,返回的是一个值。

① 结合关键字IN使用的子查询

        IN所使用的子查询主要用于判定一个给定值是否存在于在子查询的结果集中。示例如下:

/*在emp表中查询不是销售部门"SALES"的员工信息*/
select * from emp where deptno in(select deptno from dept where dname<>'SALES');

② 结合比较运算符使用的子查询

        使用比较运算符ANY,必须与单行比较运算符结合使用,并且返回行只要匹配子查询的任何一个结果即可。示例如下:

/*在emp表中查询工资大于部门编号为10的任意一个员工工资的其他部门员工信息*/
select * from emp where sal>any(select sal from emp where deptno=10) and deptno<>10

         使用比较运算符ALL,必须与单行比较运算符结合使用,并且返回行必须要匹配所有子查询结果。示例如下:

/*在emp表查询工资大于部门编号为30的所有员工工资的员工信息*/
select * from emp where sal>all(select sal from emp where deptno=30)

③ 结合关键字EXIST使用的子查询

         EXIST主要用于判定子查询的结果集是否为空,不为空则返回TRUE。示例如下:

/*emp表和dept表关联并判断当deptno>20时的员工信息*/
select * from emp e where exists(select * from dept d where e.deptno = d.deptno and deptno > 20)

        注:in和exists的区别使用exists时,数据库首先会检查主查询,然后运行子查询,找到匹配项就返回。而在执行in查询时,先将主表挂起,然后执行子查询,并将获得的结果列表放在一个加了索引的临时表中,当子查询结束后再去进行主表查询,所以当表的数据量比较大时,exists查询比in查询要快。

5、group by与having子句

        其语法结构如下:

GROUP BY {column_name|expr|position}[ASC|DESC],...[WITH ROLLUP] HAVING where_condition

        示例如下:

/*在emp表中按部门编号进行分组查询*/
select deptno from emp group by deptno;
/*在emp表中通过分组的方式计算每个部门的平均工资*/
select deptno 部门编号,avg(sal) 平均工资 from emp group by deptno;
/*在emp表中通过分组的方式计算每个部门的平均工资,再通过having子句筛选出平均工资大于2000的部门信息*/
select deptno 部门编号,avg(sal) 平均工资 from emp group by deptno having avg(sal)>2000;

注意:where与having子句非常相似,having子句支持where子句中所有的操作符和语法,但having子句支持聚合函数而where子句不支持。where子句主要用于在数据分组前进行过滤,而having子句主要用于在having子句之后进行过滤。 

6、order by子句

        ASC表示按升序进行排列,DESC表示按降序进行排列,默认的是升序。示例如下:

/*查询emp表中的所有员工信息,按照部门编号进行排序*/
select * from emp order by deptno;
/*Mysql默认是升序时NULL值在最前面,把NULL值放在最后示例*/
select * from emp order by IF(ISNULL(deptno),1,0),deptno;
/*按降序进行排列*/
select * from emp order by deptno desc;
/*Mysql默认是降序时NULL值在最后面,把NULL值放在最前面示例*/
select * from emp order by IF(ISNULL(deptno),0,1),deptno desc;

注意:order by子句中可以包含子查询。其次,当对空值进行排序时,order by子句会将该空值当作最小值来对待,按升序则放在最前面,按降序则放在最后面。上面已经给出了如何改变NULL排序的方式。 

7、limit子句

        LIMIT子句用来限制被SELECT语句返回的行数,offset为偏移量,从0开始而不是1;row_count用于返回指定的行数。

        其语法结构如下:

LIMIT {[offset,]row_count|row_count OFFSET offset}

        示例如下:

/*查询emp表的第一行数据*/
select * from emp limit 1
/*查询emp表的第10行数据*/
select * from emp limit 9,1
/*从emp表的第10行开始查询3条数据*/
select * from emp limit 9,3
select * from emp limit 3 offset 9

五、视图

        从数据库的三级模式中,可以看到模式(对应到基本表)是数据库中全体数据的逻辑结构,当不同的用户需要基本表中不同的数据时,可以为这些不同的用户建立不同的外模式。外模式的内容来源于模式,它是模式的部分数据或重构的数据。外模式对应到数据库中的概念就是视图。

        视图是数据库中的一个对象,它与数据库中真实存在的表有以下区别:

① 视图是一个虚拟表,其结构和数据是建立在对数据库中真实表的查询基础上的;

② 视图的内容是由SQL语句来定义的,它的行、列数据均来自于引用的真实表,并且这些数据在引用时动态生成;

③ 视图不是以数据集的形式存储在数据库中的,它所对应的数据是存储在真实表中的。

1、创建视图

        创建视图的语法格式如下:

CREATE VIEW view_name [(column_list)]
AS select_statement
[WITH [CASCADED|LOCAL] CHECK OPTION]

       以上语法中,WITH CHECK OPTION是一个可选项,用于指定在可更新视图上所进行的修改都需要符合查询语句中所指定的限制条件,这样可以确保数据修改后,仍可以通过视图看到修改后的数据。当视图是根据另外一个视图定义时,这个可选项给出两个参数,它们决定检查测试的范围。其中,关键字CASECADED为默认值,它会对所有视图进行检查,而关键字LOCAL则只会对定义的视图进行检查。示例如下:

create or replace view view_emp
as select * from emp where deptno = 10
with check option

2、查看视图定义

        示例如下:

show create view view_emp

3、查看视图数据

        查看视图的SQL语句跟查看基本表没什么区别,示例如下:

select * from view_emp

4、修改视图定义

        修改视图除了关键字不同,语法结构都是一样的,修改视图使用ALTER VIEW,也可以先DROP VIEW,再使用CREATE VIEW的方式来实现。示例如下:

alter view view_emp 
as select * from emp where deptno = 20
with check option

5、修改视图数据

        视图的更改是受到限制的,只有满足一定的条件时才可以进行更改操作。

⑴ 使用INSERT语句通过视图向基本表中插入数据

        示例如下:

insert into view_emp values(9999,'WANG','CLECK',8888,sysdate(),2500,200,20);

        上面这条语句是可以插入成功的,因为它满足了定义视图时WHERE子句中的条件,如果不满足就不能插入(比如将最后的deptno改成10就插入失败)。当视图所依赖的基本表有多个时,不能插入。

⑵ 使用UPDATE语句通过视图修改基本表中的数据

        示例如下:

update view_emp set comm = 500 where empno = 9999

         若一个视图依赖于多个基本表时,则一次视图修改操作只能改变一个基本表中的数据。

⑶ 使用DELETE语句通过视图删除基本表中的数据

        示例如下:

delete from view_emp where empno = 9999

        对于依赖多个基本表的视图,不能使用DELETE语句。 

6、删除视图

        示例如下:

drop view view_emp 

 

 

你可能感兴趣的:(数据库系统原理)