数据库复习总结(未写完...)

来源:互联网 发布:长城宽带是什么网络 编辑:程序博客网 时间:2024/05/21 17:47

是根据老师的ppt总结的

第一章 绪论


数据库领域的四位图灵奖得主

Charles W. Bachman(查尔斯 • 巴赫曼) 1973 主持设计与开发了最早的网状数据库管理系统IDS

Edgar F. Codd(埃德加 • 科德) 1981 提出了关系模型

James Gray(詹姆斯 • 格雷) 1998 解决保障数据的完整性、安全性、并行性,以及从故障恢复方面发挥了十分关键的作用

Michael Stonebraker (迈克尔.斯通布雷克) 2014创造了数据库系统一系列奠基性基本概念和实际技术


数据模型三要素

数据结构:记录间的组织形式

数据操纵:特定结构下的操纵功能

数据完整性约束:记录内部及记录间的限定。


数据模型的分类

层次模型

网状模型

关系模型

面向对象模型


层次模型

数据结构:树型

典型代表:IMS系统

优缺点:直观易理解,但插入和删除限制多,不方便对现实联系


网状模型

数据结构:网(有向图)

典型代表:DBTG系统

优缺点:直观描述现实世界的复杂联系,但数据库结构复杂,不利于用户掌握

关系模型

域:属性的取值范围

关系模式:对关系结构的描述

    关系名(属性1,属性2,...,属性n),例:学生(学号,姓名,性别,系)

关系应具有的六条性质:

列是同质的;

不同的列可以出自同一个域;

列序无关性;(调换列序无影响)

任意两个记录不能完全相同;(不会出现冗余的记录)

行序无关性;(调换行序无影响)

属性必须取原子值。(不可再分)


第二章 关系数据库


关系数据结构的特点:实体和联系都用关系(集合)这种单一的数据结构来实现。

关系操作的特点:
操作对象和操作结果都是集合


笛卡尔积的计算

给定域 name={王小明 ,李莉},sex={男、女}

则name×sex={ (王小明, 男),(王小明, 女),(李莉, 男),(李莉, 女)}

笛卡尔积的结果中有许多元组是无意义的,可以认为其中有意义的元组构成关系,为实际的二维表。


基本概念

候选码 (Candidate Key):能唯一标识元组的属性(组)。

主码 (Primary Key):多个候选码中选定一个作主码。

主属性 (Prime Attribute):候选码中的诸属性。

非主属性 (Non-Key Attribute):不出现在任何候选码中的属性。

例:学生学号姓名系15001蔡济民计算机15002小明数统15003小花物光

当无重名时

候选码是 学号,姓名

主属性是 学号,姓名

非主属性是 系

有时候会遇见这种情况,比如:

车牌号,车牌颜色合在一起构成一个候选码

这时候主码就是车牌号+车牌颜色

车牌号和车牌颜色都是主属性。


关系模式定义

R(U,D,dom(),F),简记为R(U)

R是关系名,U是属性集,D是关系的域,dom()属性到域上的映射关系,F函数依赖


关系的完整性约束:对关系的正确性和相容性的限定

完整性分类:

实体完整性

参照完整性

用户定义完整性


实体完整性:规则要求所有出现在候选码中的属性每个都不能为空。

参照完整性:若属性(或属性组)F是基本关系R的外码,它与基本关系S的主码Ks相对应(基本关系R和S不一定是不同的关系),则对于R中每个元组在F上的值必须为:

或者取空值(F的每个属性值均为空值)

或者等于S中某个元组的主码值

例如:

Cno

Cname

Ccredit

Cpno

c1

数据库

4

c5

c2

高等数学

2


c3

信息系统

4

c1

c5

数据结构

4

c7

c6

数据处理

2


c7

Pascal语言

4

c6

外码Cpno只能取:

(1)空值(NULL),表示该课程没有先修课

(2)非空值,这时该值必须是课程表中已有的课程号,而不能是一个不存在的课程号

用户定义完整性:如性别只能取“男”、“女”值,成绩必须在0~100分之间。通常由RDBMS的Check约束提供这类检查。


关系代数

并、交、差要求参与运算的两个关系必须具有相同的结构。

关系上的传统集合运算

并:R∪S = { t | t ∈ R∨t ∈S }

差:R – S = { t | t ∈ R∧t ∈S }

交:R∩S = { t | t ∈ R∧t ∈ S }

        R∩S = R – ( R – S )

广义笛卡尔积:R×S (其中R为k1行n列,S为k2行m列)

列:(n+m)列的元组的集合,元组的前n列是关系R的一个元组,后m列是关系S的一个元组,行:k1×k2个元组

例:RABa1b1a2b1SABa1b1a1b2

R×SR.AR.BS.AS.Ba1b1a1b1a1b1a1b1a2b1a1b1a2b1a1b2
???做笛卡尔积后会出现违反关系的任意两个记录不能完全相同的性质,就不是关系模型了么

选择(σ):σF(R) = {t | t∈R∧F(t)= '真'}

例:

Sno

Sname

Ssex

Sage

Sdept

95001

李勇

20

CS

95002

刘晨

19

IS

95003

王敏

18

MA

95004

张立

19

IS


σSsex = ‘女' (S)

Sno

Sname

Ssex

Sage

Sdept

95002

刘晨

19

IS

95003

王敏

18

MA


投影(π)

从R中选择出若干属性列组成新的关系

πA(R) = { t[A] | t ∈R }

如:

π Sno,Sname,Ssex (S)

Sno

Sname

Ssex

95001

李勇

95002

刘晨

95003

王敏

95004

张立

基础的关系查询举例:

查询信息系(IS系)全体学生 σSdept = 'IS' (Student)或 σ5 ='IS' (Student)

查询年龄小于20岁的学生σSage < '20' (Student)


连接:从两个关系的笛卡尔积中选取属性间满足一定条件的元组。连接操作是同时从行和列的角度进行运算

R

A

B

C

a1

b1

5

a1

b2

6

a2

b3

8

a2

b4

12


S

B

E

b1

3

b2

7

b3

10

b3

2

b5

2




AR.BCS.BEa1b15b27a1b15b310a1b26b27a1b26b310a2b38b310

等值连接:从关系R与S的广义笛卡尔积中选取A、B属性值相等的那些元组

自然连接(一种特殊的等值连接):两个关系中进行比较的分量必须是同名属性(组),在结果中必须把重复的属性列去掉

R

A

B

C

a1

b1

5

a1

b2

6

a2

b3

8

a2

b4

12


S

B

E

b1

3

b2

7

b3

10

b3

2

b5

2

A

R.B

C

S.B

E

a1

b1

5

b1

3

a1

b2

6

b2

7

a2

b3

8

b3

10

a2

b3

8

b3

2

 S

A

B

C

E

a1

b1

5

3

a1

b2

6

7

a2

b3

8

10

a2

b3

8

2

自然连接的意义:将两个有关联的表合成为一张信息等价的表。

除运算

R÷S = { tr [X] | tr∈R 析取 Ytr [X] 包含 πY (S) } ,其中: Y tr [X] : tr [X]在R中的象集

这个除运算的定义一般不好看

先说象集,

B

C

D

b1

c2

d1

b2

c1

d1

b2

c3

d2

CD在b2上的象集是

C

D

c1

d1

c3

d2

然后除运算就是







关系代数运算综合举例

关系模式:
S (Sno, Sname, Ssex, Sage, Sdep)

C (Cno, Cname, Ccredit, Cpno)

SC (Sno, Cno, Grade)

查询选修了C2课程的学生学号和姓名。

或是


查询选修了C2或C4课程的学生学号。


查询选修了C2和C4课程的学生学号。

错误答案:


没有任何一条记录会在一个属性列取两个不同值


或者


中间空白部分是SC

重命名(p) :ρR1 ( R ):将关系R重命名为R1;ρS( B1,B2,…,Bn ) ( R( A1,A2, …, An ) ):将关系R重命名为S,同时将关系R中的属性名A1,A2, …, An重命名为B1,B2,…,Bn 。

查询每门课的先修课的先修课(课程)


箭头忽视,老师ppt上面的,有点懒,就没去掉

查询不学C2课的学生学号

错误答案:


原因:如果该学生选c2课外还选了别的课,则非c2课的记录是符合条件的,此时会将该记录的学号置入结果集。
解决方法:先求出所有选c2课的学生,再从全体学生集合中减去这些学生。


查询选修全部课程的学生学号。


查询选修学号为“95002”的学生所选全部课程的学生学号和姓名。


总结:需要掌握的是4个传统的集合运算,交,并,差,笛卡尔积。5个专门的关系运算,选择,投影,连接,除,重命名。

关系代数表达式应该建立在关系模式上,而不是在某一特定的关系实例上满足。


第三章 关系数据库标准语言SQL

SQL的功能

数据查询 SELECT

数据定义 CREATE,DROP,ALTER

数据操纵 INSERT,UPDATE,DELETE

数据控制 GRANT,REVOKE,COMMIT,ROLLBACK

SQL与三级模式体系结构

内模式,模式和外模式,其中视图属于外模式,存储文件属于内模式,基本表属于模式。

create table stu

(

name char(8);

sno int primary key;

);


常用完整性约束

(1) 主码约束: PRIMARY  KEY

(2) 唯一性约束:UNIQUE(不能取相同值但允许多个空值)

(3) 非空值约束:NOT NULL

(4) 参照完整性约束:

 FOREIGN KEY (<列名>) REFERENCES <表名>(<列名>)

(5) CHECK约束:CHECK ( <谓词>)

(6) 断言(Assertion)约束 


主码的三种指定方式

1) 用NOT NULL  UNIQUE 作为列级约束指定

2) 用PRIMARY KEY 作为列级约束指定

3) 用PRIMARY  KEY  (<主码>) 作为表级约束指定DROP  TABLE <表名> ; 

DROP TABLE  Student ;

基本表删除后,表里的数据、表上的索引都会被删除,表上的视图往往仍然保留,但无法引用。

删除基本表时,系统会从数据字典中删去有关该基本表及其索引的描述。 

ALTER TABLE <表名>

[ ADD  <新列名>  <数据类型>  [ 完整性约束 ] ]

[ DROP  <完整性约束名>  <列名>]

[ ALTER  <列名> <数据类型> ];

<表名>:要修改的基本表

ADD子句:增加新列和新的完整性约束条件

DROP子句:删除指定的完整性约束条件

ALTER子句:用于修改列名和数据类型ALTER TABLE <表名>

例:

ALTER  TABLE  Student  ADD  Senroll  DATE ;

ALTER  TABLE  Student  ALTER  Sage  SMALLINT ;

ALTER  TABLE  Student  DROP  UNIQUE(Sname) ;

删除属性列分为直接删除(SQL-99)和间接删除

ALTER  TABLE  Student  Drop  Senroll ;


索引

分为三类,单一索引聚蔟索引普通索引 

Search-key项常用的组织方式是顺序或Hash排列。

单一索引(Unique Index):每一个索引值只对应唯一的数据记录。

聚簇索引(Cluster Index):索引项顺序与表中数据记录的物理顺序一致。

普通索引:允许一个Search-key项对应多条存储记录。

CLUSTER:表示要建立的索引是聚簇索引

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

例:为学生-课程数据库中的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) ;


删除Student表的Stusname索引。

DROP  INDEX  Stusname ;

SQL标准中没有定义对索引的修改功能,而采用删除后重新定义索引的方式实现。


数据查询

SELECT  [ ALL | DISTINCT ] <目标列表达式1> [, <目标列表达式2>] …
FROM  <表名或视图名1>[,  <表名或视图名2> ] …
[ WHERE  <条件表达式> ]
[ GROUP BY  <列名1> [ HAVING <条件表达式> ] ]
[ ORDER BY  <列名2> [ ASC | DESC ] ] ;
相关子句的说明:
SELECT子句:指定要显示的属性
FROM子句:指定查询对象(基本表或视图)
WHERE子句:指定查询条件
GROUP BY子句:对查询结果按指定列分组,列值相同的记录为一组,通常再在该组上施加集函数运算
HAVING短语:筛选出只有满足指定条件的组
ORDER BY子句:对查询结果按指定列值升序或降序排序


1)目标列(SELECT子句)为表达式的查询

查全体学生的姓名及其出生年份。
SELECT  Sname, 1996 - Sage
FROM  Student ;

2)使用列别名改变查询结果的列标题

[例5.1]  查询全体学生的姓名、出生年份和所在系,在“出生年份”前加入常数列“Year of Birth:”,用小写字母表示所有系名,并将输出字段依次更名为:NAME、BIRTH、BIRTHYEAR、DEPARTMENT。
SELECT  Sname  NAME, 'Year of Birth:'  BIRTH,
     1996 - Sage  BIRTHYEAR, 
     ISLOWER ( Sdept )  DEPARTMENT
FROM  Student ;

3)消除结果中取值重复的行
  —— 在SELECT子句中使用DISTINCT短语。

2)确定范围
[例10]  查询年龄在20~23岁(包括20岁和23岁)之间的学生的姓名、系别和年龄。
SELECT  Sname , Sdept , Sage
FROM  Student
WHERE  Sage  BETWEEN  20  AND  23 ;
3)确定集合
[例13]  查询不是信息系(IS)、数学系(MA)和计算机科学系(CS)学生的姓名和性别。
 SELECT  Sname , Ssex
FROM  Student
WHERE  Sdept  NOT  IN ( 'IS', 'MA', 'CS' ) ;


4)字符串匹配
 [NOT] LIKE  ‘<匹配模板>’  [ESCAPE ‘<换码字符>’]
匹配模板:固定字符串或含通配符的字符串。
通配符:

% (百分号):代表任意长度(可以为0)的字符串。
  例:a%b表示以a开头,以b结尾的任意长度的字符串。如acb,addgb,ab 等都满足该匹配串。

_ (下横线):代表任意单个字符。
  例:a_b表示以a开头,以b结尾的长度为3的任意字符串。如acb,afb等都满足该匹配串

当要查询的字符串本身就含有 % 或 _ 时,要使用ESCAPE '<换码字符>' 短语对通配符进行转义。

匹配模板为含通配符的字符串
[例15]  查询所有姓刘学生的姓名、学号和性别。
      SELECT  Sname , Sno , Ssex
FROM  Student
WHERE  Sname  LIKE  '刘%' ;
[例17]  查询姓名中第3个字为"阳"字的学生姓名和学号。
      SELECT  Sname , Sno
FROM  Student
WHERE  Sname  LIKE  '_ _ _ _阳%' ;


5)涉及空值的查询
使用谓词 IS NULL 或 IS NOT NULL
 “IS NULL” 不能用 “= NULL” 代替!
[例21]  某些学生选修课程后没有参加考试,所以有选课记录,但没有考试成绩。查询缺少成绩的学生的学号和相应的课程号。
SELECT  Sno , Cno
FROM  SC
WHERE  Grade  IS  NULL ;


三、对查询结果排序输出
—— 使用ORDER BY子句
可以按一个或多个属性列排序
升序:ASC;
降序:DESC;
缺省值为升序
当排序列含空值时
ASC:排序列为空值的元组最后显示
DESC:排序列为空值的元组最先显示
(将空值作为最大值来理解)

use Stu_course_mng
select *
from Student
order by Sno DESC


自身连接

SELECT  FIRST.Cno, SECOND.Cpno
FROM  Course  FIRST, Course  SECOND
WHERE  FIRST.Cpno = SECOND.Cno ; 
注:
(1) 一个表与其自己进行连接,称为表的自身连接
(2) 需要给表起别名以示区别
(3) 由于所有属性名都是同名属性,因此必须使用别名前缀


外连接(join跳过,很少用)


四、使用集函数(Aggregate Functions,聚集函数)
(1) 计数
COUNT([DISTINCT | ALL] *)
COUNT([DISTINCT | ALL] <列名>)
(2) 计算总和
SUM([DISTINCT | ALL] <列名>)
(3) 计算平均值
AVG([DISTINCT | ALL] <列名>)
(4) 求最大值
MAX([DISTINCT | ALL] <列名>)
(5) 求最小值
MIN([DISTINCT | ALL] <列名>)


查询选修c1号课程的学生最高分数。
      SELECT MAX (Grade)
FROM  SC
WHER  Cno = 'c1' ;


五、对查询结果分组输出
—— 使用GROUP BY子句分组
语法:[ GROUP BY  <列名1>[, 列名2…] [ HAVING <条件表达式> ] ] 
作用:细化集函数的作用对象

分组方法:按指定的一列或多列分组,值相等为一组
HAVING子句作用于且只能作用于各组之上
GROUP BY子句的作用对象是查询的中间结果表
未对查询结果分组,集函数将作用于整个查询结果
对查询结果分组后,集函数将分别作用于每个组 
使用GROUP BY子句后,SELECT子句的列名表中只能出现分组属性和集函数

求各个课程号及相应的选课人数。
SELECT  Cno , COUNT(Sno)
FROM  SC
GROUP  BY  Cno ;

查询有3门以上课程是90分以上的学生学号及其(90分以上的)课程数。
 SELECT  Sno , COUNT(*)
FROM  SC
WHERE  Grade >= 90
GROUP  BY  Sno
HAVING  COUNT(*) >= 3 ;


[例37]  查询与“刘晨”在同一个系学习的学生。
此查询要求可以分步来完成
① 确定“刘晨”所在系名             
SELECT  Sdept  
FROM  Student                            
WHERE  Sname = '刘晨' ;
② 查找所有所在系与上一步查询结果相等的学生。    
SELECT  Sno, Sname, Sdept
FROM  Student
WHERE  Sdept =(

SELECT  Sdept  
FROM  Student                            
WHERE  Sname = '刘晨' ;

)

执行过程:
(1) 先执行子查询,得到结果集
(2) 再执行父查询WHERE  Sdept  =  {上一步查询结果}
这种查询称为不相关子查询,即子查询的执行不依赖于父查询的条件。

采用不相关子查询的效率要优于连接查询。

返回单值时可以用 = 代替IN


三、带有ANY或ALL谓词的子查询

谓词语义:
(1) ANY ( SOME ):某些值; (2)  ALL:所有值
需要配合使用比较运算符:
> ANY 大于子查询结果中的某个值       
> ALL 大于子查询结果中的所有值
< ANY 小于子查询结果中的某个值    
< ALL 小于子查询结果中的所有值
>= ANY 大于等于子查询结果中的某个值    
>= ALL 大于等于子查询结果中的所有值
<= ANY 小于等于子查询结果中的某个值    
<= ALL 小于等于子查询结果中的所有值
= ANY 等于子查询结果中的某个值        
=ALL 等于子查询结果中的所有值(通常没有实际意义)
!=(或<>) ANY    不等于子查询结果中的某个值
!=(或<>) ALL    不等于子查询结果中的任何一个值

[例39]  查询其他系中比信息系某些学生年龄小的学生姓名和年龄。
      SELECT  Sname, Sage
FROM  Student
WHERE  Sage < ANY ( SELECT  Sage
                                          FROM  Student
                                          WHERE  Sdept = 'IS' )
    AND  Sdept <> 'IS' ;   //这是父查询块中的条件
执行过程
1. DBMS执行此查询时,首先处理子查询,找出IS系中所有学生的年龄,构成一个集合(19,18) ;
2. 处理父查询,找所有不是IS系且年龄小于19 或 18的学生。
结论:是不相关子查询

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


EXISTS谓词的意义:

是存在量词  在SQL中的应用;
带有EXISTS谓词的子查询不返回任何数据,只产生逻辑真值“True”或逻辑假值“False” ;
若内层查询结果非空,则返回真值
若内层查询结果为空,则返回假值
由EXISTS引出的子查询,其目标列表达式通常都用 * 。
因为带EXISTS的子查询只返回真值或假值,给出列名无实际意义。

查询所有选修了c1号课程的学生姓名。

SELECT  Sname
FROM  Student

WHERE  EXISTS
( SELECT    *
     FROM  SC 
 WHERE  Sno = Student.Sno  AND  Cno = 'c1' ) ;

输出那些学生的姓名,当在选课表中存在他(她)选修c1号课的记录。

(1)首先取外层查询中表的第一个元组,根据它与内层查询相关的属性值处理内层查询,若WHERE子句返回值为真,则取此元组放入结果表;
(2)然后再取外层表的下一个元组,重复这一过程,直至外层表全部检查完为止。
  此类查询称为相关子查询,即子查询的条件与父查询当前值相关。

 使用EXISTS子查询的效率要优于连接查询。

查询没有选修c1号课程的学生姓名。
SELECT  Sname
FROM  Student
WHERE  NOT  EXISTS
( SELECT  *
               FROM  SC
               WHERE  Sno=Student.Sno  AND  Cno = 'c1' ) ;
注:此查询为相关子查询,此例用连接查询无法实现!

关于EXISTS子查询的说明:
一些带EXISTS或NOT EXISTS谓词的子查询不能被其它形式的子查询等价替换。
所有带IN谓词、比较运算符、ANY和ALL谓词的子查询都能用带EXISTS谓词的子查询等价替换。
[NOT] EXISTS子查询的效率要优于连接查询和集合查询(IN谓词查询)。

查询至少选修学生95002所选全部课程的学生学号。
等价转换后的自然语义:
输出这样的学生,不存'95002'选了的课程,在他的选课记录中没有出现。
SQL语句:
SELECT   Sno
FROM  SC  SCX
WHERE  NOT  EXISTS
( SELECT  *
 FROM  SC  SCY
 WHERE  SCY.Sno = '95002'  AND  NOT  EXISTS
 ( SELECT  *
   FROM  SC  SCZ
   WHERE  SCZ.Sno = SCX.Sno AND
       SCZ.Cno = SCY.Cno )) ;

集合查询
—— 将两个SELECT – FROM – WHERE查询块用集合操作语句联结起来。
集合操作命令:
并操作(UNION)
交操作(INTERSECT)
差操作(MINUS, SQL Server 中用EXCEPT)
语句形式
<查询块>
UNION
<查询块> ;
注:参加UNION操作的各结果表的列数必须相同;对应项的数据类型也必须相同。
查询计算机系年龄不大于19岁的学生学号。
方法一:
      SELECT  Sno
FROM  Student
WHERE  Sdept = 'CS'  AND  Sage <= 19 ;
方法二:
      SELECT  Sno
FROM  Student
WHERE  Stept = 'CS'
      MINUS
      SELECT  Sno
FROM  Student
WHERE  Sage > 19 ;
查询效率:使用集合操作能更好地利用索引,效率高。
MINUS大概就是交集的意思,具体是这样的
minus指令是运用在两个 SQL 语句上。它先找出第一个 SQL 语句所产生的结果,然后看这些结果有没有在第二个 SQL 语句的结果中。如果有的话,那这一笔资料就被去除,而不会在最后的结果中出现。如果第二个 SQL 语句所产生的结果并没有存在于第一个 SQL 语句所产生的结果内,那这笔资料就被抛弃。
MINUS 的语法如下:
[SQL 语句 1]
MINUS
[SQL 语句 2]


查询注意事项:
一、别名的使用
(1) 别名用于对输出属性列的重命名
(2) 别名用于自身连接查询和对同一表的相关子查询中,用于区别对同一表的不同引用
(3) 对不相关子查询可以不使用别名
二、distinct的使用
—— DISTINCT用于区分相同的记录,将多条相同的记录作为一条处理。
三、集函数的使用
——集函数只能用于 SELECT子句和 HAVING短语之中,而绝对不能出现在 WHERE子句中(WHERE子句执行过程是对记录逐一检验,并没有结果集,故无法施加集函数)。  
错误例子:
例:查询年龄最大的学生。
      SELECT  *
FROM  Student
WHERE  Sage = MAX (Sage) ;
正确的查询语句:
      SELECT  *
FROM  Student
WHERE  Sage = ( SELECT  MAX (Sage) 
       FROM  Student ) ;
错误例子:
例:查询平均成绩最高的学生学号。
 SELECT  Sno
FROM  SC
GROUP  BY  Sno
HAVING  AVG(Grade) =
( SELECT MAX (AVG(Grade))
 FROM  SC
 GROUP  BY  Sno ) ;
注:集函数没有复合功能,换成下部分:
  HAVING  AVG(Grade) >= ALL 
( SELECT  AVG(Grade)
 FROM  SC
 GROUP  BY  Sno ) ;
四、ESIST与IN
——EXISTS通常引入的是相关子查询,而IN更多的是不相关子查询
[例] 查询所有没有选修了c1号课程的学生姓名。
(法一) SELECT  Sname
  FROM  Student
  WHERE  Sno NOT IN
( SELECT  Sno
     FROM  SC 
 WHERE  Cno = 'c1' ) ;
错误方法:
(法二) SELECT  Sname
  FROM  Student
  WHERE  NOT EXISTS
( SELECT  *
      FROM  SC   使用了分组的查询语句,其SELECT子句中只能出现分组属性和集函数,而不能有在GROUP  BY没有出现的属性。
  原因在于SELECT子句是对分组后的结果集进行输出,参与分组的属性在同一组中取相同值,而不参与分组的属性(不在GROUP  BY子句中出现的属性)则可能取不同的值,分组输出通常是对组的整体描述,而不是组内的详细记录,不参与分组的属性取值不同,故无法输出。
例:查询各系的学生人数。
      SELECT  Sdept, Ssex, COUNT(*)
FROM  Student
GROUP  BY  Sdep ;
  WHERE  Cno = 'c1' ) ;
将最后一句的WHERE改为这个就对了
WHERE Sno = Student.Sno  AND  Cno = 'c1' ) ;
五、GROUP BY的使用
GROUP  BY子句在复合查询中的应用
GROUP BY子句用来对查询结果进行分组,通常用作对各组的统计,可用于子查询。
[例50]  查询平均成绩“优秀”(>=90分)的学生学号和姓名,并按学号升序输出。
SELECT  Sno, Sname
FROM  Student
WHERE  Sno  IN
      ( SELECT  Sno
        FROM  SC
        GROUP  BY  Sno
     HAVING  AVG(Grade) >= 90 )
ORDER  BY  Sno  ASC ;

使用了分组的查询语句,其SELECT子句中只能出现分组属性和集函数,而不能有在GROUP  BY没有出现的属性。
原因在于SELECT子句是对分组后的结果集进行输出,参与分组的属性在同一组中取相同值,而不参与分组的属性(不在GROUP  BY子句中出现的属性)则可能取不同的值,分组输出通常是对组的整体描述,而不是组内的详细记录,不参与分组的属性取值不同,故无法输出。
例:查询各系的学生人数。
      SELECT  Sdept, Ssex, COUNT(*)
FROM  Student
GROUP  BY  Sdep ;
原因在于组内的性别值不同,输出值无法确定。
我敲了敲,这段的意思是这样的
use SPJ_mng
select SNO,STATUS1,count(*)
from S
group by SNO,STATUS1
SNOSTATUS1 无列名
1S1   201
2 S2   10 1
3 S3   30 1
4 S4   20 1
5 S5   30 1
如果没有STATUS1,在最后的group by里面会报错,消息 8120,级别 16,状态 1,第 2 行
选择列表中的列 'S.STATUS1' 无效,因为该列没有包含在聚合函数或 GROUP BY 子句中。
就相当于你分了两组统计了,但是并没有分两组输出

六、Order by的使用
ORDER  BY子句用于对查询结果进行排序后再输出,故只用于最外层的查询,而子查询中不应该出现ORDER BY子句。排序属性必须是SELECT子句中出现的属性。
查询学习“数据库”课程的学生学号和成绩,并按成绩由高到低进行排序。
SELECT  Sno, Grade
FROM  SC
WHERE  Cno = ( SELECT  Cno
      FROM  Course
      WHERE  Cname = '数据库' )
ORDER  BY  Grade  DESC ; 
例:查询全体学生的学号和平均成绩,并按平均成绩降序输出。
      SELECT  Sno, AVG(grade)
FROM  SC
GROUP  BY  Sno
OREDER  BY AVG(grade)  DESC;
注:ORDER  BY子句中允许出现集函数,但不具有集函数的运算功能,仅代表输出缓冲区中的列。
 也可以在SELECT子句中对集函数列进行重命名后,在ORDER BY子句中使用别名。
查询计算机系年龄不大于19岁的学生信息,并按学号升序输出。
错误答案:
      SELECT  *
FROM  Student
WHERE  Sdept = 'CS'
ORDER  BY Sno
INTERSECT
SELECT  *
FROM  Student
WHERE  Sage <= 19
ORDER  BY  Sno ;
中间多了一个ORDER BY SNO
因为Order by只用于最外层的查询排序

七、输出多个表的属性的查询
  查询的输出只能取自最外层查询所使用的表,对于子查询中的属性是不能作为最终的输出的。如果输出的属性涉及多个表,则最外层查询只能使用连接查询。 
例:查询成绩超过80分的学生学号、姓名、课程号和成绩。
错误答案:
  SELECT  DISTINCT  Sno, Sname, Cno, Grade
  FROM  Student
  WHERE  Sno  IN ( SELECT  Sno
         FROM  SC
     WHERE  Grade >= 80 ) ;
  正确的查询语句:
        SELECT  Sno, Sname, Cno, Grade
  FROM  Student, SC
  WHERE  Student.Sno = SC.Sno  AND  Grade >= 80 ;
八、导出关系作为数据源的使用
子查询的结果集可以看作基本关系一样作为查询的数据源,需要对结果集命名别名以便引用。
例:查询全体学生的学号、姓名和平均成绩。
      SELECT  Sno, Sname, avg_grade
FROM  Student, ( SELECT  Sno, AVG(Grade)  AS 
   avg_grade
      FROM  SC
    GROUP  BY  Sno )  AS  SC_AVG
WHERE  Student.Sno = SC_AVG.Sno ;
九、SQL性能优化拾遗(应该跟考试无关吧)
第一个原则:在WHERE子句中应把最具限制性的条件放在最前面
例:
(1) SELECT  *
FROM  table1
WHERE  field1 <= 10000  AND  field1 >= 0 ;
(2) SELECT  *
FROM  table1
WHERE  field1 >= 0  AND  field1 <= 10000 ;    
    如果数据表中数据的 field1 值大部分都>=0,则语句(1) 要比语句(2) 效率高得多,因为语句(2)的第一个条件耗费了大量的系统资源。
第二个原则: WHERE子句中字段的顺序应和索引中字段顺序一致
例:
SELECT  *
FROM  tab
WHERE  a =…  AND  b =…  AND  c =… ;
  若有索引INDEX(a,b,c),则WHERE子句中字段的顺序应和索引中字段顺序一致。

数据更新
一、插入数据
(1) 插入单个元组 —— 新元组插入指定表中。
  语句格式:
INSERT
INTO  <表名>  [(<属性列1>[, <属性列2 >…)]
VALUES  (<常量1> [, <常量2>]    … ) ;
注:
INTO子句
指定要插入数据的表名及属性列
属性列的顺序可与表定义中的顺序不一致
没有指定属性列:表示要插入的是一条完整的元组,且属性列属性与表定义中的顺序一致
指定部分属性列:插入的元组在其余属性列上取空值
VALUES子句
 提供的值的个数和值的类型必须与INTO子句匹配
将一个新学生记录 ( 学号:95020;姓名:陈冬;性别:男;所在系:IS;年龄:18岁 ) 插入到Student表中。
INSERT
INTO  Student
VALUES   ( '95020' , '陈冬' , '男' , 'IS' , 18) ; 
插入一条选课记录( '95020', '1' )。
INSERT
INTO   SC ( Sno, Cno )
VALUES  ( '95020' ,'1' ) ;
注:新插入的记录在Grade列上取空值。
??? 问题:若待插入记录未指定值的列在表上是NOT NULL约束会如何?
二、修改数据
语句格式:
UPDATE  <表名>
SET  <列名>=<表达式>[, <列名>=<表达式>]…
[WHERE  <条件>] ;
功能:
修改指定表中满足WHERE子句条件的元组。
注:
SET子句 —— 指定修改方式,要修改的列和修改后取值
WHERE子句
指定要修改的元组
缺省表示要修改表中的所有元组
(1) 用WHERE子句指定修改单个记录
[例4]  将学生95001的年龄改为22岁。
UPDATE  Student
SET  Sage = 22
WHERE  Sno = '95001' ;
(2) 用WHERE子句(或不用)指定修改多个记录
[例5]  将所有学生的年龄增加1岁。
 UPDATE  Student
SET  Sage = Sage+1 ;
[例6]  将信息系所有学生的年龄增加1岁。
 UPDATE  Student
SET  Sage = Sage+1
WHERE  Sdept = 'IS' ;

(3) 用子查询指定要修改的记录
错误答案:
[例7]  将计算机科学系全体学生的成绩置零。
 UPDATE  SC
SET  Grade = 0
WHERE  ( SELECT  Sdept
      FROM  Student
      WHERE  Student.Sno = SC.Sno ) = 'CS' ;
正确的语句:
UPDATE  SC
SET  Grade = 0
WHERE  'CS'=
      ( SELECT  Sdept
               FROM  Student
               WHERE  Student.Sno = SC.Sno ) ;
这个是不能放在后面就是匹配的字符串
三、删除数据
语句格式:
DELETE
FROM  <表名>
[WHERE  <条件>] ;
功能
删除指定表中满足WHERE子句条件的元组
注:
WHERE子句
指定要删除的元组
缺省表示要修改表中的所有元组

???delete 通常是删除单条或多条记录,drop是删除一个表
(3) 用子查询指定要删除的记录
[例11]  删除计算机科学系所有学生的选课记录。
      DELETE
FROM  SC
WHERE  Sno  IN ( SELECT  Sno
        FROM  Student
        WHERE  Student.Sdep = 'CS' ) ;
  或
DELETE
FROM  SC
      WHERE  'CS' =
             ( SELECT  Sdept
             FROM  Student
                      WHERE  Student.Sno = SC.Sno ) ; 

删除数据有时候会破坏完整性规则
第一种是不允许删除,第二种是级联删除