数据库整理(三) SQL基础

SQL语言的特点

集数据定义语言(DDL),数据操纵语言(DML),数据控制语言(DCL)功能于一体。

可以独立完成数据库生命周期中的全部活动:

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

​ ●对数据库中的数据进行查询和更新

​ ●数据库重构和维护。

​ ●数据库安全性、完整性控制,以及事务控制。

​ ●嵌入式SQL和动态SQL定义

1.用户在数据库系统投入运行后还可根据需要随时地、逐步地修改模式,并不影响数据库的运行,系统具有良好的可扩展性

2.在关系模型中实体和实体间的联系均用关系表示,这种数据结构的单一性带来了数据操作符的统一性,查找、插入、删除、更新等每一种操作都只需一种操作符,从而克服了非关系系统由于信息表示方式的多样性带来的操作复杂性。

3.“过程化”语言完成某项请求必须指定存取路径。SQL进行数据操作时,只要提出“做什么”,而无须指明“怎么做”,因此无须了解存取路径。存取路径的选择以及SQL的操作过程由系统自动完成。减轻了用户负担,而且有利于提高数据独立性。

4.面向集合的操作方式非关系数据模型采用的是面向记录的操作方式,操作对象是一条记录。例如查询所有平均成绩在80分以上的学生姓名,用户必须一条一条地把满足条件的学生记录找出来(通常要说明具体处理过程,即按照哪条路径,如何循环等)。而SQL采用集合操作方式,不仅操作对象、查找结果可以是元组的集合,而且一次插入、删除、更新操作的对象也可以是元组的集合

5.SQL既是独立的语言,又是嵌入式语言。SQL语句能够嵌入到高级语言(例如C、C++、Java)程序中,供程序员设计程序时使用。

SQL三级结构

支持SQL的关系数据库管理系统同样支持关系数据库三级模式结构。其中外模式包括若干视图(view)和部分基本表( base table),数据库模式包括若干基本表,内模式包括若干存储文件( stored file)。

用户可以用SQL对基本表和视图进行查询或其他操作,基本表和视图一样,都是关系基本表是本身独立存在的表,在关系数据库管理系统中一个关系就对应一个基本表

一个或多个基本表对应一个存储文件,一个表可以带若干索引,索引也存放在存储文件中

存储文件的逻辑结构组成了关系数据库的内模式。存储文件的物理结构对最终用户是隐蔽的

视图是从一个或几个基本表导出的表。它本身不独立存储在数据库中,即数据库中只存放视图的定义而不存放视图对应的数据。这些数据仍存放在导出视图的基本表中,因此视图是个虚表。视图在概念上与基本表等同,用户可以在视图上再定义视图。

数据定义

一个关系数据库管理系统的实例( Instance)中可以建立多个数据库,一个数据库中可以建立多个模式,一个模式下通常包括多个表、视图和索引等数据库对象。

SQL还可以定义:用户、触发器、过程与函数等

关于模式与数据库用户区别的理解

(参考 https://blog.csdn.net/FallingU/article/details/78955707

什么是User,什么是Database,什么是Schema,什么是Table,什么是列,什么是行?

可以把Database看作是一个大仓库,仓库分了很多很多的房间,Schema就是其中的房间,一个Schema代表一个房间,Table可以看作是每个Schema中的,Table就被放入每个房间中,不能放置在房间之外。然后床上可以放置很多物品,就好比Table上可以放置很多列和行一样。所以Schema包含的是Object,而不是User

User是每个对应数据库的主人,既然有操作数据库的权利,就肯定有操作数据库中每个Schema(房间)的权利。换句话说,如果他是某个仓库的主人,那么这个仓库的使用权和仓库中的所有东西都是他的,他有完全的操作权,。我们还可以给其他User分配具体的权限,也就是他到某一个房间能做些什么,是只能看(Read-Only),还是可以像主人一样有所有的控制权(R/W),这个就要看这个User所对应的角色Role了

默认情况下一个用户对应一个集合,用户的schema名等于用户名,并作为该用户缺省schema。所以schema集合看上去像用户名。访问一个表时,如果没有指明该表属于哪个schema,系统会自动加上缺省的schema。一个对象的完整名称为schema.object,而不属user.object

在MySQL中创建一个Schema和创建一个Database的效果好像是一样的,但是在SQL Server和Oracle数据库中效果又是不同的。

在SQL Server中,假如我们在某一数据库中创建了用户Bosco,那么此时后台也为我们默认的创建了schema【Bosco】,schema的名字和user的名字相同。

模式与表

create table A时,如果没有特定的Schema做前缀,这个A表创建在了哪个Schema上,即进入了哪个房间?答案是:

  1. 如果当前操作数据库的用户有默认的Schema(在创建用户的时候指定了),那么表A被创建在了默认的Schema上。

  2. 如果当前操作数据库的用户没有默认的Schema(即在创建User的时候默认为空),那么表A被创建在了dbo Schema上, dbo房间(schema)好比一个大的公共房间,在当前登录用户没有默认schema的前提下,如果你在大仓库中进行一些操作,比如create table,如果没有制定特定的房间(schema),那么你的物品就只好放进公共的dbo房间(schema)了。

  3. 如果在创建表A的时候指定了特定的Schema做前缀,则表A被创建在了指定的 Schema上。

当定义基本表时一般可以有三种方法定义它所属的模式:

(定义一个学生一课程模式ST,现在要在ST中定义 Student、 Course、SC等基本表)

方法一:在表名中明显地给出模式名。

CREATE TABLE "S-T". Student(···)/*Student所属的模式是S-T*/

方法二,在创建模式语句中同时创建表。

方法三,设置所属的模式,这样在创建表时表名中不必给出模式名

模式创建的作用

例如你的数据库里面有很多的表。就以一个学校作为例子吧:

有很多表分别用于存储学生、课程、成绩、学分等信息。还有很多表用于存储 老师、工资、奖金等信息。如果这么多的表,都混杂在一起。管理起来非常麻烦。

通过 create schema , 划分区域, 把学生的,创建一个 schema 叫 Student,教师的,创建一个 schema 叫 Teacher

这样,对于专门负责学生信息管理的,就只负责 Student 这个 schema,表名全部是 Student.具体表名。

模式(架构)

类似命名空间(集合),里面用来存放该模式包含的各种数据库对象,在CREATE SCHEMA中可以接受CREATE TABLE,CREATE VIEW和GRANT子句。

CREATE SCHEMA <模式名> AUTHORIZATION <用户名>[<表定义子句>|<视图定义子句>|<授权定义子句>]

如果没有指定<模式名>,那么<模式名>隐含为<用户名>

创建模式,调用该命令的用户必须拥有数据库管理员权限,或者获得了数据库管理员授予的 CREATE SCHEMA的权限

CREATE  SCHEMA  TEST  AUTHORIZATION  ZHANG
CREATE TABLE TAB1(COL1 SMALLINT, COL2 INT, COL3 CHAR(20),
COL4 NUMERIC(10,3), COL5 DECIMAL(5,2) );

​ 为用户 ZHANG 创建了一个模式TEST,并在其中定义了一个表 TAB1

删除模式

    DROP SCHEMA <模式名> <CASCADE|RESTRICT>

CASCADE(级联)

删除模式的同时把该模式中所有的数据库对象全部删除。

RESTRICT(限制)--默认

如果该模式中定义了下属的数据库对象(如表、视图等),则拒绝该删除语句的执行。当该模式中没有任何下属的对象时才能执行。

数据字典

数据字典是一个预留空间,一个数据库,这是用来储存信息数据库本身关系数据库管理系统在执行SQL的数据定义语句时,实际上就是在更新数据字典表中的相应信息。在进行查询优化和查询处理时,数据字典中的信息是其重要依据

基本表

定义基本表

CREATE TABLE < [架构名.] 表名 >(<列名> <数据类型>[ <列级完整性约束条件> ]  [,<列名> <数据类型>[ <列级完整性约束条件>] ] …[,<表级完整性约束条件> ] );

完整性约束条件被存入系统的数据字典中,当用户操作表中数据时由关系数据库管理系统自动检查该操作是否违背这些完整性约束条件。如果完整性约束条件涉及该表的多个属性列,则必须定义在表级上,否则既可以定义在列级也可以定义在表级

主码是必须的

建立Students表,学号是主码,姓名取值唯一

CREATE TABLE Students
(Sno char(10) PRIMARY KEY, /* 列级完整性约束条件*/
Sname varchar2(20) UNIQUE, /* Sname取唯一值*/
Ssex char(2) DEFAULT '男', /* 默认男性*/
/* Ssex char(2) CHECK(Ssex IN ('男',‘女’))*/
Sage Smallint CHECK(Sage>10 AND Sage<25),/*Check短语指定列表应满足的条件*/
Mno char(2), /* 专业号*/
Class char(1) /* 班级 */
);
建立Course表

      CREATE TABLE  Course
( Cno char(4) PRIMARY KEY,
Cname varchar(20) NOT NULL, /*列级完整性,Cname不取空值*/
Credit number(3,1),
Pcno char(4) , /* Pcno是先修课 */
FOREIGN KEY (Pcno) REFERENCES Course(Cno)
/*表级完整性 定义Pcno为外码, 被参照表是Course, 被参照列是Cno*/
);
建立一个学生选课表SC

	CREATE TABLE  SC(
Sno char(10), Cno CHAR(4),
Grade number(3),
PRIMARY KEY (Sno,Cno),
/* 主码由两个属性构成,必须作为表级完整性进行定义*/
FOREIGN KEY (Sno) REFERENCES Students(Sno),
/* 表级完整性约束条件,Sno是外码,被参照表是Students */
FOREIGN KEY (Cno) REFERENCES Course(Cno)
/* 表级完整性约束条件, Cno是外码,被参照表是Course*/
);

数据类型

数据类型 含义
CHAR(m) 长度为n的定长字符串
VARCHAR(n) 最大长度为n的变长字符串
INT 长整数(4字节)
SMALLINT 短整数(2字节)
BIGINT 大整数(8字节)
FLOAT(n) 可选精度的浮点数,精度至少为n位数字
BOOLEAN 逻辑布尔量
DATE 日期,包含年、月、日,格式为 YYYY-MM-DD
TIME 包含一日的时、分、秒,格式为 HH:MM:SS

修改基本表

ALTER TABLE < [架构名.] 表名 >
[ ADD [Column] <新列名> <数据类型> [ 完整性约束 ] ]
[ ADD <表级完整性约束> ]
[ DROP [Column] <列名> [ CASCADE | RESTRICT ]]
[ DROP CONSTRAINT <完整性约束名> ]
[ ALTER Column <列名> <数据类型> ];

ADD子句用于增加新列、新的列级完整性约束条件和新的表级完整性约束条件。

DROP COLUMN子句用于删除表中的列,如果指定了 CASCADE短语,则自动删除引用了该列的其他对象.如果指定了 RESTRICT短语,则如果该列被其他对象引用, RDBMS将拒绝删除该列。

DROP CONSTRAINT子句用于删除指定的完整性约束条件。

ALTER COLUMN子句用于修改原有的列定义,包括修改列名和数据类型。

对现存列改名
ALTER TABLE distributors RENAME COLUMN address TO city;
增加新列
ALTER TABLE Student ADD S_entrance DATE;
修改列的数据类型
ALTER TABLE Student Alter Column Sno number(10);
增加课程名称必须唯一的完整性约束
ALTER TABLE Course ADD UNIQUE(Cname);

删除基本表

 DROP TABLE < [架构名.] 表名 >[RESTRICT| CASCADE];

RESTRICT:删除表是有限制的。

​ 欲删除的基本表不能被其他表的约束所引用

​ 不能有视图,不能有触发器等

​ 如果存在依赖该表的对象,则此表不能被删除

CASCADE:删除该表没有限制。

​ 在删除基本表的同时,相关的依赖对象一起删除 视图、索引、触发器等

​ 该基本表被其他基本表引用,这些表也会被删除(执行删除基本表的操作务必谨慎)

​ (例如:选课表表通过外码Sno引用 Student,Student表删除,选课表也被级联删除)

索引

当表的数据量比较大时,查询操作会比较耗时。建立索引是加快查询速度的有效手段

可以根据需要在基本表上建立一个或多个索引,以提供多种存储路径,加快查找速度

索引虽然能够加速数据库查询,但需要占用一定的存储空间,当基本表更新时,索引要相应的维护,这些都会增加数据库的负担,因此要根据实际应用的需要有选择地创建索引(并非越多越好)

索引

数据库系统是“懒”的,除非必要,否则不会替用户做多余的事情(比如排序和建立多余的索引)

谁可以建立索引

  • DBA 或 表的属主(即建立表的人)

  • DBMS一般会自动建立以下列上的索引(两者都是唯一的,数据更新的时候方便判断,加快速度

    PRIMARY KEY

    UNIQUE

谁维护索引?

​ DBMS自动完成

使用索引

		DBMS自动选择是否使用索引以及使用哪些索引,用户不能显式地选择索引

​ --属于内模式的范围 当一些极端情况,使用索引速度比不使用还慢或者使用不同的索引类型效果不一样。

建立索引

CREATE  [UNIQUE] [CLUSTER]  INDEX  <索引名>
ON <表名>(<列名>[<次序>][,<列名>[<次序>] ]…)

<表名>是要建索引的基本表的名字。索引可以建立在该表中一或多列上,各列名之间用逗号分隔。每个<列名>后面还可以用<次序>指定索引值的排列次序,可选ASC(升序)或DESC(降序),默认值为ASC。

UNIQUE表明此索引的每一个索引值只对应唯一的数据记录;CLUSTER表示要建立的索引是聚簇索引。

(把属性上具有相同值的元组集中存放在连续的物理块中成为聚簇,改属性(属性组)称为聚簇码)

(如要查询计算机系的所有学生信息,可能分散在不同地方,建立索引避免全表扫描)

(聚簇操作适用一个或一组属性的值重复率很高的情况,对其他属性可能反而增加了查询时间,其他属性可能更加分散

一个基本表最多建立一个聚簇索引

为学生-课程数据库中的 Student、 Course和SC三个表建立索引。其中Student表按学号升序建唯一索引, Course表按课程号升序建唯一索引,SC表按学号升序和课程号降序建唯一索引。

CREATE UNIQUE INDEX Stusno ON Student(Sno):
CREATE UNIQUE INDEX Coucno ON Course( Cno):
CREATE UNIQUE INDEX SCno ON SC(Sno ASC, Cno DESC)

修改索引

ALTER INDEX<旧索引名> RENAME TO<新索引名>;

删除索引

DROP INDEX <索引名>  ON <表名>;

索引建立之后由系统维护,避免维护索引的时间过多,删除不必要的索引

删除索引时,会同时从数据字典中删除相关描述

数据查询

SELECT [ALL|DISTINCT] <目标列表达式> [,<目标列表达式>] …
FROM <表名或视图名>[, <表名或视图名> ] …
[ WHERE <条件表达式> ]
[ GROUP BY <列名1> [ HAVING <条件表达式> ] ]
[ ORDER BY <列名2> [ ASC|DESC ] ];

整个 SELECT语句的含义是:

  • 根据 WHERE子句的条件表达式从FROM子句指定的基本表、视图或派生表中找出满足条件的元组,再按 SELECT子句中的目标列表达式选出元组中的属性值形成结果表。
  • 如果有 GROUP BY子句,则将结果按<列名1>的值进行分组,该属性列值相等的元组为一个组。通常会在每组中作用聚集函数。
  • 如果 GROUP BY子句带 HAVING短语,则只有满足指定条件的组才予以输出。
  • 如果有 ORDER BY子句,则结果表还要按<列名2>的值的升序或降序排序。
  • SELECT语句既可以完成简单的单表查询,也可以完成复杂的连接查询和嵌套查询。

参数的说明:

  • ALL为默认,保留重复的行 DISTINCT取消重复的行
  • 目标列表达式有:算数表达式、字符串变量、函数、列别名等 --类似“投影”操作
  • FROM R1,R2 相当于构建R1*R2的笛卡尔积
  • WHERE 相当于选择操作
  • GROUP 类似聚集函数,进行分组聚集
  • ORDER 排序,可以多个属性排列 ,分割 先按第一属性升序(降序),再按第二属性升序(降序)

单表查询

选择表中的部分列

Select Sno, Sname, Year(Date())-Sage From  Student;/*  表达式,函数  */
/* <目标表达式>不仅仅可以是属性列 也可以是表达式 Year(Date())-Sage表示的是当前时间-年龄 即出生年 Year是函数*/ Select Sno 学号,Sname 姓名,‘合肥工业大学’ 学校 From Student;/* 列别名,字符串常量 */
/* 最终的查询表为:学号、姓名、学校 其中第三列的值是一样的,查询常量得到的结果就是常量值本身*/ /*查询全体学生的姓名、出生年份和所在的院系,要求用小写字母表示系名。*/
SELECT Sname, 'Year of Birth:' Birth,2014-Sage Year, LOWER(Sdept) sdept FROM Student. /*LOEWE函数*/
Sname 'Year of Birth:' Year sdept
李勇 'Year of Birth:' 1994 cs
刘晨 'Year of Birth:' 1995 cs
王丽 'Year of Birth:' 1996 ma
张丽 'Year of Birth:' 1995 is

选择表中的部分元组

查询满足条件的元组可以通过WHERE子句实现,WHERE子句常用的查询条件:

Select Distinct Sno  From  SC  Where  Grade < 60;        /*  比较大小   */
Select Sno,Sname From Student Where Sage Not Between 20 and 23; /* 确定范围 */
Select Sno, Sname From Student Where Sage in (19,21,22); /* 确定集合 */
/* 字符匹配: [Not] Like '<匹配串>' [ Escape '换码字符' ] */
Select * From Student Where Sname Like '宋%' ;/* 通配符:% ,_ */
Select Sno, Cno From SC Where Grade is Not Null; /* 涉及空值的查询 IS NULL 或 IS NOT NULL */
Select Sno From SC Where Cno='2008' and Grade>90; /*多重条件查询*/
/*逻辑运算符AND和OR可用来连接多个查询条件。AND的优先级高于OR,但用户可以用括号改变优先级。*/

<匹配串>可以是一个完整的字符串,也可以含有通配符%和_。其中:

  • %(百分号)代表任意长度(长度可以为0)的字符串。例如a%b表示以a开头,以b结尾的任意长度的字符串。
  • _(下横线)代表任意单个字符

OREDER BY子句

  • 可以按一个或多个属性列排序
  • 升序:Asc;降序:DESC;缺省值为升序
  • 当排序列含空值时

    Asc:排序列为空值的元组最后显示;

    DEsc:排序列为空值的元组最先显示。
	SELECT * FROM Student ORDER BY Sdept, Sage DESC;
/* 查询全体学生情况,查询结果按所在系的系号升序排列,同一系中的学生按年龄降序排列*/

聚集函数只用于SELECT和HAVING中

一般用于统计

当聚集函数遇到空值时,除 COUNT( * )外,都跳过空值而只处理非空值。 COUNT( * )是对元组计数

COUNT(*) 统计元组个数
COUNT(【 DISTINCT I ALL】<列名>) 统计一列中值的个数
SUM(【 DISTINCT | ALL】<列名>) 计算一列值的总和(此列必须是数值型)
AVG(【 DISTINCT | ALL】<列名>) 计算一列值的平均值(此列必须是数值型)
MAX(【 DISTINCT | ALL】<列名>) 求一列值中的最大值
MIN(【 DISTINCT | ALL】<列名>) 求一列值中的最小值

如果指定 DISTINCT短语,则表示在计算时要取消指定列中的重复值。如果不指定DISTINCT短语或指定ALL短语(ALL为默认值),则表示不取消重复值

SELECT AVG(Grade) ,MAX(Grade)  FROM SC  WHERE Cno= '2010';/*查询2010课程的平均分与最高分*/
SELECT SUM(Ccredit) FROM SC,Course WHERE SnO='1' AND SC.Sno=Course.Cno/*查询1号学生选修课程的总学分*/

GROUP BY子句

GROUP BY子句将查询结果按某一列或多列的值分组,值相等的为一组。

对查询结果分组的目的是为了细化聚集函数的作用对象。如果未对查询结果分组,聚集函数将作用于整个查询结果。分组后聚集函数将作用于每一个组,即每一组都有一个函数值

作用对象是查询的中间结果表

SELECT Cno,COUNT(Sno) FROM SC GROUP BY Cno; /*查询各个课程号及相应的选课人数*/
/*该语句对查询结果按Cno的值分组,所有具有相同Cno值的元组为一组,然后对每一组作用聚集函数 COUNT进行计算,以求得该组的学生人数 */
Cno COUNT(Sno)
1 22
2 34
3 44
4 33
5 48

可以使用HAVING对这些组再进行删选

SELECT Sno FROM SC GROUP BY Sno HAVING COUNT(*)>3

HAVING与WHERE区别

​ WHERE子句与 HAVING短语的区别在于作用对象不同。 WHERE子句作用于基本表或视图,从中选择满足条件的元组。 HAVING短语作用于组,从中选择满足条件的组。

连接查询 ---连接操作

若一个查询同时涉及两个以上的表,则称之为连接査询。

连接操作的执行过程

  • 嵌套循环法

    首先在表 Student中找到第一个元组,然后从头开始扫描SC表,逐一查找与 Student第一个元组的Sno相等的SC元组,找到后就将 Student中的第一个元组与该元组拼接起来,形成结果表中一个元组。SC全部查找完后,再找 Student中第二个元组……重复上述操作,直到 Student中的全部元组都处理完毕为止

    特点是:简单但是时间慢

  • 排序合并法

    要求表是有序的

  • 索引连接

    如果在SC表Sno上建立了索引的话,就不用每次全表扫描SC表了,而是根据Sno值通过索引找到相应的SC元组

等值连接 (条件表达式的连接运算符是“=”)

SELECT  Student.*, SC.*  FROM    Student, SC  WHERE  Student.sno = SC.sno;
/*表名前缀,是为了避免混淆。如果属性名在参加连接的各表中是唯一的,则可以省略表名前缀。*/

自然连接 (把目标列中重复的属性列去掉)

自身连接 (一个表与自己连接)

SELECT FIRST.Cno,SECOND.Cpno FROM Course FIRST Course SECOND WHERE FIRST.Cpno-SECOND.Cno
/*为COURSE表设置两个别名*/

外连接 把悬浮元组(不满足连接条件的元组)保存在结果关系中

左外连接列出左边关系中所有的元组,右外连接列出右边关系中所有的元组。

SELECT Student.Sno, Sname, Ssex, Sage, Sdept, Cno, Grade FROM Student LEFT OUTER JOIN SC ON (Student Sno=SC Sno);

多表连接

一般是先进行两个表的连接操作,再将其连接结果与第三个表进行连接。 注意选择表的顺序

嵌套查询

在SQL语言中,一个 SELECT-FROM- WHERE语句称为一个查询块。将一个查询块嵌套在另一个查询块的 WHERE子句或 HAVING短语的条件中的查询称为嵌套查询

查询每个学生的学号、姓名、选修的课程名及成绩
循环嵌套:
SELECT Sname /*外层查询或父查询*/
FROM Student WHERE Sno IN
(SELECT Sno FROM SC WHERE Cno=2) /*内层查询或子查询*/
多表连接:
SELECT Student.Sno Sname, Cname,Grade FROM Student, SC ,Course
WHERE Student.Sno=SC.Sno AND SC. Cno=Course.Cno:
两种方式:先从SC中挑选出Cno=2并且 Grade>90的元组形成一个中间关系,再和 Student中满足连接条件的元组进行连接得到最终的结果关系。减少了连接时的代价,更为优化

先选择投影再进行连接

SQL语言允许多层嵌套查询。子查询的 SELECT语句中不能使用 ORDER BY子句, ORDER BY子句只能对最终结果进行排序,可以使用GROUP BY语句。 子查询的结果是一个表(关系)

有些嵌套查询可以用连接运算代替,有些不能;

嵌套查询逻辑更为清晰,但优化还不是很好,尽可能使用连接运算

相关子查询与不相关子查询

子查询的查询条件不依赖于父查询称为不相关子查询。 ---能单独执行子查询的是不相关子查询

非相关子查询是独立于外部查询的子查询,子查询总共执行一次,执行完毕后将值传递给外部查询。

相关子查询的执行依赖于外部查询的数据,外部查询执行一行,子查询就执行一次

非相关子查询比相关子查询效率高

带有ANY(SOME)或ALL谓词的子查询

查询其他专业中比软件工程专业任意一个(其中某一个)学生年龄小的学生。
Select * From Student
Where Sage <ANY ( Select Sage
From Student Where mno='03')
AND mno <> '03' ;
/* 注意:这是父查询块中的条件 */

ANY和ALL谓词有时可以用聚集函数实现,ANY与AL与聚集函数的对应关系如下表:

= <>或!= < <= > >=
ANY IN -- <MAX <=MAX >MIN >=MIN
ALL -- NOT IN <MIN <=MIN >MAX >=MAX

用聚集函数实现子查询通常比直接用ANY或ALL查询效率要高,因为前者通常能够减少比较次数:

SELECT Sname.Sage FROM Student WHERE Sage<
(SELECT MAX(Sage)
FROM Student WHERE Sdept='CS)
AND Sdept"Cs’

使用ANY和ALL谓词:(一定是相关的)

​ 首先处理子查询,找出CS系中所有学生的年龄,构成一个集合(假设20,19):然后处理父查询,找所有不是CS系 且年龄小于20或19的学生本查询

使用聚集函数:

​ 首先用子查询找出CS系中最大年龄(20),然后在父查询中查所有非CS系且年龄小于20岁的学生

明显比较次数要少,效率更高

EXISTS谓词(存在量词彐)

  • 带有 EXISTS谓词的子查询不返回任何数据,只产生逻辑真值“true“或逻辑假值“ false",若内层查询结果非空,则外层的 WHERE子句返回真值,若内层查询结果为空,则外层的 WHERE子句返回假值
  • 由 EXISTS引出的子查询,其目标列表达式通常都用*,因为带 EXISTS的子查询只返回真假值,给列名无实际意义。
/*查询所有选修了2010号课程的学生姓名*/
Select Sname From Student Where Exists (Select *
From SC Where Sno=Student.Sno AND Cno= '2010');/*存在量词*/ Select Sname
From Student, SC
Where Student.Sno=SC.Sno AND SC.Cno= '2010';/*有些可以转化为连接查询*/ Select Sname
From Student Where Sno in
(Select Sno from SC Where Sno=Student.Sno and Cno='2010'/*优化*/

使用EXISTS谓词的是相关查询,效率较低,可以将其转化为不相关查询,提交效率 SQL语言中没有

全称量词

可以把带有全称量词的谓词转换为等价的带有存在量词的谓词:

( ∀ x)P ≡ ┐ ( ∃ x( ┐ P))

逻辑蕴含

SQL语言中没有逻辑蕴涵运算,可以利用谓词演算将逻辑蕴涵谓词等价转换为: p→q≡ ┐ p∨q

问题:查询至少选修了学生20160002选修的全部课程的学生学号

用逻辑蕴涵表达:查询学号为x的学生,对所有的课程y,只要95002学生选修了课程y,则x也选修了y

变换后语义:不存在这样的课程y,学生95002选修了y,而学生x没有选
SELECT DISTINCT X.Sno FROM SC X /*对于学生X*/
WHERE NOT EXISTS( /*不存在*/
SELECT * FROM SC Y /*这样一门课, 95002选了*/
WHERE Y.Sno = 95002 AND NOT EXISTS( /*X没有选*/
SELECT * FROM SC Z
WHERE Z.Cno = Y.Cno AND Z.Sno = X.Sno
)
);/*Cno是课程号,Sno是学号*/

集合查询

	**参加集合操作的各查询结果的列数必须相同;对应项的数据类型也必须相同**

SELECT语句的查询结果是元组的集合,所以多个 SELECT语句的结果可进行集合操作。集合操作主要包括并操作UNION、交操作 INTERSECT和差操作 EXCEPT

UNION:将多个查询结果合并起来时,系统自动去掉重复元组。

UNION ALL:将多个查询结果合并起来时,保留重复元组

查询同时选修了课程2008和课程2010的学生学号。

方法一:集合查询
Select Sno From SC Where Cno= '2008'
INTERSECT
Select Sno From SC Where Cno= '2010'; 方法二:嵌套查询
Select Sno From SC Where Cno= '2008' AND Sno IN
(Select Sno From SC Where Cno= '2010');

基于派生表的查询

子查询不仅可以出现在 WHERE子句中,还可以出现在FROM子句中,这时子查询生成的临时派生表成为主查询的查询对象。

查询选课超过三门的学生的学号、姓名、性别
Select Student.Sno, Sname, Ssex
From Student, (Select Sno, Count(*) From SC
Group By Sno Having Count(*) > 3 )
AS SSC(Sno, Cnt)/*生成选课统计表:学号 选课数*/
Where Student.Sno = SSC.Sno;
查询每个学生超过他自己选修课程平均成绩的课程号
Select Sno,Cno
From Sc,(Select Sno,AVG(Grade) From SC Group by Sno)
As Avg_sc(avg_sno,avg_grade)
Where Sc.Sno=Avg_sc.avg_sno and Sc.Grade>=Avg_sc.avg_grde
查询所有选修1号课程的学生姓名
Select Sname
From Student ,(Select Sno From Sc Where Cno='1')
As Sc1(Sno)
Where Student.Sno=Sc1.Sno
使用With子句改写:
With Sc1(Sno) As
Select Sno From Sc Where Cno='1'
Select Sname
From Sc1,Student
Where Student.Sno=Sc1.Sno

AS 建立的是一个临时的派生表,在基本表里面是没有的 AS 后面是别名 便于使用

数据更新

插入、修改、删除 ---数据更新过程中注意操作的完整性检查 更新表时按照规则逐一检查

插入数据

插入元组和插入子查询的结果,后者可以一次性插入多个元组

插入元组
INSERT INTO <表名> [(<属性列1>[,<属性列2 >…)]
VALUES (<常量1> [,<常量2>] … )
插入子查询结果
INSERT INTO <表名> [(<属性列1> [,<属性列2>… )] 子查询;

功能是将新元组插入指定表中。其中新元组的属性列1的值为常量1,属性列2的值为常量2,…。INTO子句中没有出现的属性列,新元组在这些列上将取空值。但在表定义时说明了 NOT NULL的属性列不能取空值,否则会出错。

INTO子句中没有指明任何属性列名,新插入的元组必须在每个属性列上均有值次序与 CREATE TABLE中的次序相同

元组:插入一条学生选课元组
Insert into SC(Sno, Cno) Values('20160001', '2008'); 子查询:对每一个专业,计算学生的平均年龄,并把结果存入数据库。 第一步:建基本表majors_age
Create table majors_age (mno char(2), avg_age number(3,1)); 第二步:插入数据
Insert into majors_age(mno,avg_age)
select mno, avg(age) from Student group by mno;

修改数据(更新)

UPDATE  <表名>   SET  <列名>=<表达式>[,<列名>=<表达式>]…
[WHERE <条件>];

功能:修改指定表中满足 WHERE子句条件的元组。省略了WHERE子句,表示要修改表中的所有元组

方式:

(1)修改某一个元组的值

(2)修改多个元组的值

(3)带子查询的修改(子查询可以嵌套在UPDATE子句中)

修改某一个元组的值
将学生201215121的年龄改为22岁。
UPDATE Student SET Sage=2
WHERE Sno='201215121';
修改多个元组的值
将所有学生的年龄增加1岁。
UPDATE Student
SET Sage=Sage+1:
带子查询
将计算机科学系全体学生的成绩置零。
UPDATE SC SET Grade=0
WHERE Sno IN (SELETE Sno FROM Student WHERE Sdept='CS');

删除数据

DELETE  FROM     <表名>   [WHERE <条件>];

删除指定表中满足 WHERE子句条件的元组。缺省表示要删除表中的全部元组,表的定义仍在字典中。

删除的是表中的数据,而不是关于表的定义 --删除一个元组 多个元组 删除带子查询的

空值

“不知道无意义”的值

SQL语言中允许某些元组的某些属性在一定情况下取空值。一般有以下几种情况:

  • 该属性应该有一个值,但目前不知道它的具体值。例如,某学生的年龄属性,因为学生登记表漏填了,不知道该学生年龄,因此取空值。
  • 该属性不应该有值。例如,缺考学生的成绩为空,因为他没有参加考试。
  • 由于某种原因不便于填写。例如,一个人的电话号码不想让大家知道,则取空值因此,空值是一个很特殊的值,含有不确定性,对关系运算带来特殊的问题,需要做特殊的处理。

空值判断使用 IS NULL

属性定义(或域定义)中有 NOT NULL约束的不能取空值,加了 UNIQUE限制的属性不能取空值(码属性不能取空值)

视图

  • 视图是从一个或几个基本表(或视图)导出的表。它与基本表不同,是一个虚表
  • 数据库中只存放视图的定义,而不存放视图对应的数据,这些数据仍存放在原来的基本表中。
  • 一旦基本表中的数据发生变化,从视图中查询出的数据也就随之改变了。从这个意义上讲,视图就像一个窗口,透过它可以看到数据库中自己感兴趣的数据及其变化。
  • 视图一经定义,就可以和基本表一样被查询、被删除。
  • 可以在一个视图之上再定义新的视图,但对视图的更新(增、删、改)操作则有一定的限制。
  • 视图与基本表呈现给用户时都是二维表
  • 视图的定义存放于数据字典中 基本表的定义存放在数据字典中 但还有数据存储在其他地方
  • 基于视图的操作: 查询、删除、受限更新、定义基于该视图的新视图
  • 数据更新最好交给基本表,视图应该主要用于查询

创建视图

CREATE  VIEW    <视图名>  [(<列名>  [,<列名>]…)]
AS <子查询> [WITH CHECK OPTION];
  • 组成视图的属性列名:全部省略或全部指定
  • 子查询不允许含有 ORDER BY子句和 DISTINCT短语。
  • RDBMS执行 CREATE VIEW语句时只将视图定义存入数据字典,并不执行其中的 SELECT 语句。视图查询时,才会按照视图的定义从基本表中将数据查出
  • 视图查询时,其数据来源于相关基本表。
  • WITH CHECK OPTION 表示对视图进行 UPDATE、 INSERT和 DELETE操作时要保证更新、插入或删除的行满足视图定义中的谓词条件(即子查询中的条件表达式)。
建立计算机系(0001)选修了2010号课程的学生视图。
CREATE VIEW v_0001_2010(Sno,Sname,Grade) AS
SELECT s.sno, sname, grade FROM v_dept_student s, sc
WHERE s.sno=sc.sno and s.dno=‘0001’ and sc.cno='2010'
WITH CHECK OPTION;/* 以后对该视图进行插入、删除、修改操作时都会加上WHERE的条件*/

视图不仅可以建立在一个或多个基本表上,也可以建立在一个或多个已定义好的视图上,或建立在基本表与视图上

定义基本表时,为了减少数据库中的冗余数据,表中只存放基本数据,由基本数据经过各种计算派生出的数据一般是不存储的。由于视图中的数据并不实际存储,所以定义视图时可以根据应用的需要设置一些派生属性列。这些派生属性由于在基本表中并不实际存在,也称它们为虚拟列。带虚拟列的视图也称为带表达式的视图。

CREATE VIEW BT S(Sno, Sname, Birth AS
SELECT Sno, Sname, Year(Date())-Sage FROM Student:/*Birth就是基本属性导出的*/

删除视图

DROP  VIEW  <视图名> [CASCADE];/*会删除视图定义*/

如果该视图上还导出了其他视图,使用 CASCADE级联删除语句,把该视图和由它导出的所有视图一起删除

删除基表时,由该基表导出的所有视图都没有用了,但是视图定义还在,都必须显式地使用DROP VEW语句删除。

查询视图

用户角度:查询视图与查询基本表是相同的

查询时优先查询基本表,若同一架构中基本表与视图的名称相同会导致视图失效

定义视图并查询视图与基于派生表的查询是有区别的视图一旦定义,其定义将永久保存在数据字典中,之后的所有查询都可以直接引用该视图。而派生表只是在语句执行时临时定义,语句执行后该定义即被删除

RDBMS实现视图查询:

1.视图消解法

  • 1.进行有效性检查---检查查询中涉及的表、视图等是否存在
  • 2.转化为等价的对基本表的查询。视图存在,从数据字典中取出视图的定义,把定义中的子查询和用户的查询结合起来,转换成等价的对基本表的查询
  • 3.执行修正了的查询
  • 问题:不能确保转换的正确性--目前一般只有行列子集视图可以正确转换(若一个视图是从单个基本表导出的,并且只是去掉了基本表的某些行和某些列,但保留了主码,则称这类视图为行列子集视图。)

2.实体化视图(优先)

  • 有效性检查
  • 执行视图定义,生成临时表
  • 查询视图转化为查询临时表
  • 查询完毕后删除实体化的视图

更新视图

  • 插入、删除、修改操作

  • 视图是不实际存储数据的虚表,因此对视图的更新最终要转换为对基本表的更新

  • 为防止用户通过视图对数据进行增加、删除、修改时,有意无意地对不属于视图范围内的基本表数据进行操作,可在定义视图时加上 WITH CHECK OPTION子句。这样在视图上增、删、改数据时,关系数据库管理系统会检查视图定义中的条件,若不满足条件则拒绝执行该操作。

  • 部分视图是不可更新的(视图的更新无法转变为对应基本表的更新) 一般:行列式视图可以更新

  • DB2规定:视图由两个以上基本表导出的,视图是不可更新的【区别于不允许更新,后者有可能是可更新的,但系统不允许】

视图的作用

1. 视图能够简化用户的操作; 简单好用的虚表 用户看来跟基本表是一样的

2. 视图使用户能以多种角度看待同一数据;

3. 视图对重构数据库提供了一定程度的逻辑独立性; 外模式保持不变,应用程序保持不变

4. 视图能够对机密数据提供安全保护; 给视图权限,不给数据基本表的权限 例如:本院老师只能看本院学生信息

5. 适当的利用视图可以更清晰的表达查询。

数据库整理(三) SQL基础的更多相关文章

  1. Oracle数据库之PL/SQL基础

    介绍PL/SQL之前,先介绍一个图像化工具:Oracle SQL Developer 在oracle的开发过程中, 我们难免会使用第三方开发的软件来辅助我们书写SQL, pl/sql是一个不错的sql ...

  2. <三> SQL 基础

    SQL查询的一般形式,以及被逻辑处理的顺序 (8) select (9) distinct (11) <TOP_specification> <select_list> (1) ...

  3. SQL基础-->层次化查询(START BY ... CONNECT BY PRIOR)[转]

    --====================================================== --SQL基础-->层次化查询(START BY ... CONNECT BY ...

  4. SQL基础--&gt;层次化查询(START BY ... CONNECT BY PRIOR)

    --====================================================== --SQL基础-->层次化查询(START BY ... CONNECT BY ...

  5. ASP.NET实现二维码 ASP.Net上传文件 SQL基础语法 C# 动态创建数据库三(MySQL) Net Core 实现谷歌翻译ApI 免费版 C#发布和调试WebService ajax调用WebService实现数据库操作 C# 实体类转json数据过滤掉字段为null的字段

    ASP.NET实现二维码 using System;using System.Collections.Generic;using System.Drawing;using System.Linq;us ...

  6. [SQL] SQL 基础知识梳理(一)- 数据库与 SQL

    SQL 基础知识梳理(一)- 数据库与 SQL [博主]反骨仔 [原文地址]http://www.cnblogs.com/liqingwen/p/5902856.html 目录 What's 数据库 ...

  7. [SQL] SQL 基础知识梳理(三) - 聚合和排序

    SQL 基础知识梳理(三) - 聚合和排序 [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5926689.html 序 这是<SQL 基础知识梳理 ...

  8. Sql基础(零基础学数据库_SqlServer版)

    刚开始学C#时候的笔记,只是些基础的语句如有错误请批评指正,谢谢,(使用SqlServer2012以上) 一.  数据库概述 SQI全称 structrued Query Language 1.数据: ...

  9. 【学习记录】第一章 数据库设计-《SQL Server数据库设计和开发基础篇视频课程》

    一.课程笔记 1.1  软件开发周期 (1)需求分析阶段 分析客户的业务和数据处理需求. (2)概要设计阶段 设计数据库的E-R模型图,确认需求信息的正确和完整. /* E-R图:实体-关系图(Ent ...

随机推荐

  1. pycharm安装Numba失败问题

    相关环境变量: pycharm Python 3.8 pip 19.3.1 Numba各个版本都不行 报错内容: Looking in indexes: https://pypi.tuna.tsing ...

  2. 四使用浮动div布局

    刚开始学习的小白,如有不足之处还请各位补充,感激涕零.在html中有两种方式布局<table>表格和<div>,个人剧的使用表格布局可以避免bug产生,并且表格布局相对来说要容 ...

  3. html5学习之路_001

    安装环境 安装intellij idea作为开发环境 打开环境 新建一个html文件,打开之后出现代码框架,再次基础上继续编码即可,例如: <!DOCTYPE html> <html ...

  4. vc程序设计-----位图

    // resource_study.cpp : 定义应用程序的入口点. // #include "framework.h" #include "resource_stud ...

  5. python通用数据库操作工具 pydbclib

    pydbclib是一个通用的python关系型数据库操作工具包,使用统一的接口操作各种关系型数据库(如 oracle.mysql.postgres.hive.impala等)进行增删改查,它是对各个p ...

  6. Chisel3 - 使用chisel-iotesters进行验证

    https://mp.weixin.qq.com/s/KqyklKrPLtPm38sftMYlHA   1. 使用Maven获取库   Chisel相关的库基本上都可以使用Maven获取到(https ...

  7. 跨域解决方案 - JSONP

    目录 1. 定义 2. JSONP 解决跨域 3. 应用场景 4. 代码演示 1. 定义 在HTML 中, script 标签有两个个性质: script 标签可以不受同源策略的限制去访问服务器资源, ...

  8. Java实现 蓝桥杯VIP 算法训练 会议中心

    算法训练 会议中心 时间限制:2.0s 内存限制:512.0MB 会议中心 Siruseri政府建造了一座新的会议中心.许多公司对租借会议中心的会堂很感兴趣,他们希望能够在里面举行会议. 对于一个客户 ...

  9. Java实现 蓝桥杯 算法提高 数组求和

    试题 算法提高 数组求和 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 输入n个数,围成一圈,求连续m(m<n)个数的和最大为多少? 输入格式 输入的第一行包含两个整数n, ...

  10. Java实现硬币收集问题

    1 问题描述 在n*m格木板中放有一些硬币,每格的硬币数目最多为一个,在木板左上方的一个机器人需要收集尽可能多的硬币并把它们带到右下方的单元格.每一步,机器人可以从当前的位置向右移动一格或向下移动一格 ...