结构化查询语言SQL包括:数据定义语言DDL、数据操纵语言DML、数据控制语言DCL和其它。
数据库中的关系集合必须由SQL的数据定义语言DDL(data definition language)来定义。
包括:数据库、关系模式、每个属性的值域、完整性约束、每个关系的索引集合和关系的物理存储结构等
SQL数据定义语言DDL包括:
建立学生成绩数据库ScoreDB
CREATE DATABASE ScoreDB
ON -- 定义第一个逻辑设备(默认为主逻辑设备)及其数据文件
( NAME=ScoreDB, -- 数据文件的逻辑文件名(即别名)
FILENAME='e:\SQLDatabase\ScoreDB.mdf', -- 物理(磁盘)文件名
SIZE=2,
MAXSIZE=10, //限制maxsize 使得别人无法在攻破数据库后,无限塞垃圾
FILEGROWTH=1 ) //初始是2兆,每次增加1兆
LOG ON -- 定义日志逻辑设备及其日志文件
( NAME=ScoreLog, -- 日志文件的逻辑文件名(即别名)
FILENAME='e:\SQLDatabase\ScoreLog.ldf', -- 日志(磁盘)文件名
SIZE=1,
MAXSIZE=5,
FILEGROWTH=1 )
建立一个复杂的数据库MyTempDB
CREATE DATABASE MyTempDB
ON
PRIMARY -- 定义主逻辑设备及其数据文件
( NAME = TempDev, -- 数据文件的逻辑文件名(即别名)
FILENAME ='d:\TempData\TempDev.mdf', -- 物理(磁盘)文件名
SIZE = 5,
FILEGROWTH = 2 ),
FILEGROUP TempHisDev -- 定义第1个用户逻辑设备组的名称及数据文件
( NAME = TempHisDev1, -- 数据文件的逻辑文件名(即别名)
FILENAME ='d:\TempData\TempHisDev1.mdf', -- 物理文件名
SIZE = 10,
FILEGROWTH = 5 ),
FILEGROUP TempBakDev -- 定义第2个用户逻辑设备组的名称及其数据文件
( NAME = TempBakDev1, --该用户逻辑设备组中第1个数据文件的逻辑文件名
FILENAME ='d:\TempData\TempBakDev1.mdf', --该数据文件的物理文件名
SIZE = 5, FILEGROWTH = 2 ),
( NAME = TempBakDev2, -- 该用户逻辑设备组中第2个数据文件的逻辑文件名
FILENAME ='d:\TempData\TempBakDev2.mdf', --该数据文件的物理文件名
SIZE = 5, FILEGROWTH = 2 ),
( NAME = TempBakDev3, -- 该用户逻辑设备组中第3个数据文件的逻辑文件名
FILENAME ='d:\TempData\TempBakDev3.mdf', --该数据文件的物理文件名
SIZE = 5, FILEGROWTH = 2 )
LOG ON -- 定义日志逻辑设备及其日志文件
( NAME ='TempLogDev1', -- 日志逻辑设备中第1个日志文件的逻辑文件名
FILENAME ='d:\TempData\TempLogDev1.ldf', --该日志文件的物理文件名
SIZE = 5MB, FILEGROWTH = 2MB ),
( NAME ='TempLogDev2', -- 日志逻辑设备中第2个日志文件的逻辑文件名
FILENAME ='d:\TempData\TempLogDev2.ldf', --该日志文件的物理文件名
SIZE = 5MB, FILEGROWTH = 2MB )
修改MyTempDB数据库
ALTER DATABASE MyTempDB
MODIFY FILE ( NAME = TempHisDev1,
SIZE = 20MB )
将逻辑文件名(即别名)为TempHisDev1的磁盘文件的初始大小修改为20M
删除数据库时,系统会同时从系统的数据字典中将该数据库的描述一起删除
有的数据库系统会自动删除与数据库相关联的物理文件
删除数据库操作的语法为:
DROP DATABASE <databaseName>
其中:image为存储图象的数据类型,text存放大文本数据
建立学生成绩管理数据库中的5张基本表。
CREATE TABLE Course ( -- 创建课程表Course
courseNo char(3) NOT NULL, --课程号
courseName varchar(30) UNIQUE NOT NULL, --课程名
creditHour numeric(1) DEFAULT 0 NOT NULL, --学分
courseHour tinyint DEFAULT 0 NOT NULL, --课时数
priorCourse char(3) NULL, --先修课程
/* 建立命名的主码约束和匿名的外码约束 */
CONSTRAINT CoursePK PRIMARY KEY (courseNo),
FOREIGN KEY (priorCourse) REFERENCES Course(courseNo)
) -- 外码约束是匿名的
CREATE TABLE Class ( -- 创建班级表Class
classNo char(6) NOT NULL, --班级号
className varchar(30) UNIQUE NOT NULL, --班级名
institute varchar(30) NOT NULL, --所属学院
grade smallint DEFAULT 0 NOT NULL, --年级
classNum tinyint NULL, --班级人数
CONSTRAINT ClassPK PRIMARY KEY (classNo)
)
CREATE TABLE Term ( -- 创建学期表Term
termNo char(3) NOT NULL, --学期号
termName varchar(30) NOT NULL, --学期描述
remarks varchar(10) NULL, --备注
CONSTRAINT TermPK PRIMARY KEY (termNo)
)
CREATE TABLE Student ( -- 创建学生表Student
studentNo char(7) NOT NULL
CHECK (studentNo LIKE '[0-9][0-9][0-9][0-9][0-9][0-9][0-9]'), --学号
studentName varchar(20) NOT NULL, --姓名
sex char(2) NULL, --性别
birthday datetime NULL, --出生日期
native varchar(20) NULL, --籍贯
nation varchar(30) DEFAULT ‘汉族’ NULL, --民族
classNo char(6) NULL, --所属班级
CONSTRAINT StudentPK PRIMARY KEY (studentNo),
CONSTRAINT StudentFK FOREIGN KEY (classNo)
REFERENCES Class(classNo)
)
CREATE TABLE Score ( -- 创建成绩表Score
studentNo char(7) NOT NULL , --学号
courseNo char(3) NOT NULL , --课程号
termNo char(3) NOT NULL, --学期号
score numeric(5, 1) DEFAULT 0 NOT NULL , --成绩
/* 建立由3个属性构成的命名的主码约束 */
CONSTRAINT ScorePK
PRIMARY KEY (studentNo, courseNo, termNo),
/* 建立三个命名的外码约束 */
CONSTRAINT ScoreFK1 FOREIGN KEY (studentNo)
REFERENCES Student(studentNo),
CONSTRAINT ScoreFK2 FOREIGN KEY (courseNo)
REFERENCES Course(courseNo),
CONSTRAINT ScoreFK3 FOREIGN KEY (termNo)
REFERENCES Term(termNo)
)
通过ALTER TABLE命令修改基本表的结构,如扩充列等.
修改基本表操作的语法为(为待修改表的名称):
增加列(新增一列的值为空值):
ALTER TABLE <tableName>
ADD <columnName> <dataType>
增加约束:
ALTER TABLE <tableName>
ADD CONSTRAINT <constraintName>
删除约束:
ALTER TABLE <tableName>
DROP <constraintName>
修改列的数据类型:
ALTER TABLE <tableName>
ALTER COLUMN <columnName> <newDataType>
//在MyTempDB数据库中为TempTable表增加一列。
ALTER TABLE TempTable
ADD xsex int DEFAULT 0
//在MyTempDB数据库中为TempTable表的xname 列修改数据类型。
ALTER TABLE TempTable
ALTER COLUMN xname char(10)
//在MyTempDB数据库中为TempTable表的xname列增加唯一约束
ALTER TABLE TempTable
ADD CONSTRAINT UniqueXname UNIQUE (xname)
// 注意:基本表在修改过程中,不可以删除列,一次仅执行一种操作。
DROP TABLE TempTable
如在班级表Class中按所属学院建立索引InstituteIdx
//对班级表Class按所属学院建立非聚集索引InstituteIdx.
CREATE NONCLUSTERED INDEX InstituteIdx
ON Class(institute)
// 在学生表Student中,首先按班级编号的升序,然后按出生日期的降序建立一个非聚集索引ClassBirthIdx。
CREATE INDEX ClassBirthIdx
ON Student(classNo, birthday DESC)
//删除班级表Class中建立的InstituteIdx索引。
DROP INDEX InstituteIdx ON Class
数据操纵语言DML(data manipuplation language) 主要用于对数据库的数据进行检索(查询)和更新。
SQL数据更新语句包括三条:插入INSERT、删除DELETE和修改UPDATE。
INSERT INTO Student
VALUES ( '0700006', '李相东', '男', '1991-10-21 00:00', '云南',
'撒呢族', 'CS0701' )
//本例表名Student后没有指定属性名,表示按照Student表定义的属性列的个数和顺序将新元组插入到Student表中。
INSERT INTO Student(studentName, birthday, studentNo)
VALUES ( '章李立', '1991-10-12 00:00', '0700007' )
//本例按照指定属性的顺序和属性的个数向学生表Student插入一个新元组,没有列出的属性列自动取空值NULL或默认值;
//插入新元组时,数据的组织可不按照基本表结构定义的属性个数和顺序进行插入。
//首先,创建基本表StudentNation:
CREATE TABLE StudentNation (
studentNo char(7) NOT NULL , --学号
courseNo char(3) NOT NULL , --课程号
termNo char(3) NOT NULL, --学期号
score numeric(5, 1) DEFAULT 0 NOT NULL --成绩
CHECK( score BETWEEN 0.0 AND 100.0),
CONSTRAINT StudentNationPK
PRIMARY KEY (studentNo, courseNo, termNo)
)
//然后,执行如下插入语句:
INSERT INTO StudentNation
SELECT *
FROM Score
WHERE studentNo IN (
SELECT studentNo FROM Student WHERE nation<>'汉族' )
此处注意表定义与子查询结构的一致性
INSERT INTO StudentNation(studentNo, courseNo, termNo)
SELECT studentNo, courseNo, termNo
FROM Score
WHERE studentNo IN (
SELECT studentNo
FROM Student
WHERE nation='汉族' )
//该查询仅将汉族同学的学号、课程号和学期号插入到基本表StudentNation中;
//成绩列自动取0值,而不是空值NULL,这是因为在定义基本表StudentNation时该列设置了默认值为0。
删除学号为1600001同学的选课记录。
DELETE FROM Score
WHERE studentNo='1600001'
[例1] 删除选修了“高等数学”课程的选课记录。
DELETE FROM Score
WHERE courseNo IN (
SELECT courseNo
FROM Course
WHERE courseName='高等数学' )
[例2] 删除平均分在60到70分之间的同学的选课记录
DELETE FROM Score
WHERE studentNo IN (
SELECT studentNo
FROM Score
GROUP BY studentNo
HAVING avg(score) BETWEEN 60 AND 70 )
UPDATE Score
SET score=88
WHERE courseNo='002' AND termNo='151'
AND studentNo IN
( SELECT studentNo FROM Student
WHERE studentName='王红敏' )
也可以写成:
UPDATE Score
SET score=88
FROM Score a, Student b
WHERE a.studentNo=b.studentNo AND courseNo='002'
AND termNo='151' AND studentName='王红敏'
UPDATE Score
SET score=score+5
FROM Score a, Student b, Class c
WHERE a.studentNo=b.studentNo AND b.classNo=c.classNo
AND className='注册会计16_02班' AND sex='男'
UPDATE Student
SET birthday='1999-5-6 00:00', native='福州'
WHERE studentNo='0800001'
注意:插入、删除和修改操作会破坏数据的完整性,如果违反了完整性约束条件,其操作会失败。
4.将每个班级的学生人数填入到班级表的ClassNum列中。
UPDATE Class
SET classNum=sCount
FROM Class a,
( SELECT classNo, count(*) sCount
FROM Student
GROUP BY classNo ) b
WHERE a.classNo=b.classNo
CREATE VIEW StudentView1999
AS
SELECT *
FROM Student
WHERE year(birthday)=1999 -- 创建视图中的谓词条件
本例省略了视图的列名,自动取查询出来的列名。
- 本例没有使用WITH CHECK OPTION选项,下面的插入语句可以执行:
INSERT INTO StudentView1999 VALUES
('1500008', '李相东', '男', '1998-10-21 00:00', '云南', '撒呢族', 'CS1501')
- 但是, 对视图StudentView1999查询时却不能查询出刚插入的元组, 因为刚插入的学生元组并不满足创建视图中的谓词条件。
CREATE VIEW StudentView1999Chk
AS
SELECT *
FROM Student
WHERE year(birthday)=1999 -- 创建视图中的谓词条件
WITH CHECK OPTION
本例建立的视图StudentView1999Chk,其更新操作必须满足:
修改操作:自动加上year(birthday)=1999的条件;
删除操作:自动加上year(birthday)=1999的条件;
插入操作:自动检查是否满足条件year(birthday)=1999 ,如果不满足,则拒绝该插入操作。
由于使用了WITH CHECK OPTION选项,下面的插入语句可以执行:
INSERT INTO StudentView1999Chk VALUES
(‘1500008’, ‘李相西’, ‘男’, ‘1999-10-21 00:00’, ‘云南’, ‘撒呢族’, ‘CS1501’)
下面的插入语句不可以执行:
INSERT INTO StudentView1999Chk VALUES
(‘0700009’, ‘李相南’, ‘男’, ‘1998-10-21 00:00’, ‘云南’, ‘撒呢族’, ‘CS1501’)
由于成绩必须大于等于60分才获得学分,该视图必须含有该条件
CREATE VIEW ScoreView
AS
SELECT a.studentNo, studentName, courseName, creditHour, score
FROM Student a, Course b, Score c
WHERE a.studentNo=c.studentNo AND b.courseNo=c.courseNo
AND score>=60 -- 成绩必须大于等于60分才能获得学分
但是,如果某学生选修某门课程2次且都考试及格,则视图的查询结果中会出现2次。
CREATE VIEW SourceView(courseNo, courseName, courseCount, courseAvg)
AS
SELECT a.courseNo, courseName, count(*), avg(score)
FROM Course a, Score b
WHERE a.courseNo=b.courseNo
GROUP BY a.courseNo, courseName
本例使用聚合函数,必须为视图的属性命名,可在视图名的后面直接给出列名,也可用下面的语句替代:
CREATE VIEW SourceView1
AS
SELECT a.courseNo, courseName, count(*) courseCount, avg(score) courseAvg
FROM Course a, Score b
WHERE a.courseNo=b.courseNo
GROUP BY a.courseNo, courseName
CREATE VIEW SourceView2
AS
SELECT *
FROM SourceView
WHERE courseCount>=5
CREATE VIEW StudentAgeView
AS
SELECT studentNo, studentName, year(getdate())-year(birthday) age
FROM Student
SELECT *
FROM StudentView1999
WHERE classNo='CS1601'
对于该查询:
系统首先进行有效性检查:判断视图StudentView1999是否存在?
如果存在,则从系统的数据字典中取出该创建视图的语句;
将创建视图中的子查询与用户的查询结合起来,转换为基于基本表的查询,即将视图StudentView1999的定义转换该查询为:
- SELECT *
- FROM Student
- WHERE year(birthday)=1999 AND classNo=‘CS1601’
然后系统执行改写后的查询。
SELECT *
FROM SourceView
WHERE courseAvg>=80
视图SourceView是一个基于聚合运算的视图,列是courseAvg,它是经过聚合函数运算的值。
HAVING子句可以对聚合函数直接作用,系统会将该查询转换为如下的形式:
- SELECT a.courseNo, courseName, count(*) courseCount, avg(Score)
courseAvg- FROM Course a, Score b
- WHERE a.courseNo=b.courseNo
- GROUP BY
a.courseNo, courseName
HAVING avg(score)>=80
—————————————— 分界线 —————————————
UPDATE StudentView1999
SET studentName='张小立'
WHERE studentNo='1600004'
相当于
UPDATE Student
SET studentName='张小立'
WHERE year(birthday)=1999 AND studentNo='1600004'
UPDATE StudentView1999
SET birthday='2000-05-20 00:00:00.000'
WHERE studentNo='1600004'
在视图StudentView1999Chk中不能将出生年份修改为2000,因为该视图对修改操作进行了检查(即检查修改后的结果是否满足创建视图中的谓词条件)。
DELETE FROM StudentView1999
WHERE studentNo='1600006'
系统将操作转化为
DELETE FROM Student
WHERE year(birthday)=1999 --创建视图中的谓词条件
AND studentNo='1600006'
DELETE FROM SourceView
WHERE courseAvg>=80
DELETE FROM SourceView
WHERE courseAvg>=80
对于该操作,数据库管理系统拒绝执行
因为视图SourceView中包含了聚合运算,系统无法将该视图转化为对基本表的操作。
//删除视图StudentView1991:
DROP VIEW StudentView1991
//级联删除视图SourceView:
DROP VIEW SourceVIEW CASCADE