定义数据库包括定义数据库名、确定数据库文件及其大小、确认日志文件的位置和大小。定义数据库使用CREATE DATABASE语句,其语法格式为
CREATE DATABASE <数据库名>
[ON [PRIMARY] ( [NAME = <逻辑数据文件名>,]
FILENAME =’<操作数据文件路径和文件名>’
[, SIZE = <文件长度>] [, MAXSIZE = <最大文件长度>]
[, FILEGROWTH = <文件增长率>]) [,…n]]
[LOG ON ([NAME=〈逻辑日志文件名〉,]
FILENAME= ’〈操作日志文件路径和文件名〉’
[, SIZE=〈文件长度〉] )[ ,…n]]
[FOR RESTORE]
例:创建数据库“学生选课库”,初始大小为4MB。
CREATE DATABASE 学生选课库
ON PRIMARY
(
NAME=学生选课库,
FILENAME = ‘C:\SQLSERVER\DATA\学生选课.mdf’, --根据要存储的路径修改
SIZE = 4MB,
MAXSIZE = 6MB,
FILEGROWTH = 20%
)
DROP DATABASE <数据库名>
创建数据表:数据表是关系数据库的基本组成单位,它物理地存储于数据库的存储文件中
CREATE TABLE [<库名.>]<表名>
(
<列名> <数据类型> [列级完整性约束条件][,<列名> <数据类型> [列级完整性约束条件]]
[, …n]
[,<表级完整性约束条件>][, …n] )= 20%
)
列约束:是对某一个特定列的约束,包含在列定义中,直接跟在该列的其他定义之后,
用空格分隔,不必指定列名。
表约束:与列定义相互独立,不包括在列定义中,通常用于对多个列一起进行约束,
定义表约束时必须指出要约束的那些列的名称。完整性约束的基本语法格式为:
[ CONSTRAINT <约束名> ] <约束类型>
约束名:约束不指定名称时,系统会给定一个名称
(1)NULL/NOT NULL
(2)UNIQUE约束:UNIQUE约束用于指明基本表在某一列或多个列的组合上的取值必须唯一
例:建立一个Student表,定义Sname + Sex 为唯一码。
CREATE TABLE Student
(
Sno CHAR(5) NOT NULL,
Sname VARCHAR(20),
Sex CHAR(1),
Sdept VARCHAR(15),
Smon CHAR(5),
SBirthDay SMALLDATETIME,
CONSTRAINT S_UNIQ UNIQUE(Sname,Sex)
(3)PRIMARY KEY约束:用于定义基本表的主码,起唯一标识作用,其值不能为NULL,也不能重复,以此来保证实体的完整性。
PRIMARY KEY与UNIQUE约束类似,通过建立唯一索引来保证基本表在主码列取值的唯一性,主要区别在于:
①在一个基本表中只能定义一个PRIMARY KEY约束,但可定义多个UNIQUE约束;
②对于指定为PRIMARY KEY的一个列或多个列的组合,其中任何一个列都不能出现空值,而对于UNIQUE所约束的唯一键,则允许为空。
[CONSTRAINT <约束名>] FOREIGN KEY (<外码>)
REFERENCES <被参照关系名> (<列名>[{<列名>}])
(5)CHECK约束:CHECK约束用来检查字段值所允许的范围,如,一个字段只能输入整数,而且限定在0-100的整数,以此来保证域的完整性。
CHECK既可用于列约束,也可用于表约束,其语法格式为:
[CONSTRAINT <约束名>] CHECK (<条件>)
例:建立一个SC表,定义SCORE的取值范围为0~100之间
CREATE TABLE SC
( Sno CHAR(5),
Cno CHAR(5),
SCORE DECIMAL(4,1)
CHECK(SCORE>=0 AND SCORE <=100)
)
ALTER TABLE〈表名〉
[ADD〈新列名〉〈数据类型〉[列完整性约束] ]
[DROP 〈完整性约束名〉]
[MODIFY〈列名〉〈数据类型〉]
(1)ADD方式
注意:使用此方式增加的新列自动填充NULL值,所以不能为增加的新列指定NOT NULL约束。
例: 在SC表中增加完整性约束定义,使SCORE在0~100之间。
ALTER TABLE SC ADD CONSTRAINT SCORE_CHK
CHECK ( SCORE BETWEEN 0 AND 100 )
(2)DROP方式
使用DROP语句删除指定的完整性约束条件
例: 删除SC表中的SCORE_CHK约束。
ALTER TABLE SC DROP SCORE_CHK
(3)MODIFY 方式
例:把S表中的SNO列加宽到8位字符宽度
ALTER TABLE S MODIFY COLUMN SNO CHAR(8)
注意:使用此方式有如下一些限制:
①不能改变列名;
②不能将含有空值的列的定义修改为NOT NULL约束;
③若列中已有数据,则不能减少该列的宽度,也不能改变其数据类型;
④只能修改NULL|NOT NULL约束,其它类型的约束在修改之前必须先删除,然后再重新添加修改过的约束定义。
drop table <表名>
(1)定义索引
语法格式为:
CREATE [UNIQUE] [CLUSTER] INDEX <索引名>
ON <表名>(<列名>[<次序>][,<列名>[<次序>] ]…)
其中:
1)UNIQUE表示要建立唯一索引,此索引的每一个索引值只对应唯一的数据记录。
2)CLUSTER表示要建立的索引是聚簇索引。索引可以建立在该表的一列或多列上,各列名之间用逗号分隔。
3)可用<次序>指定索引值的排列次序,升序ASC,降序DESC,默认为ASC。
例:为Student,Course,SC三个表建立索引。其中Student表按学号升序建唯一索引,Course表按课程号升序建唯一索引,SC表按学号升序和课程号降序建唯一索引。
CREATE UNIQUE INDEX S_Sno ON Student (Sno)
CREATE UNIQUE INDEX C_Cno ON Course(Cno)
CREATE UNIQUE INDEX SCno ON SC(Sno ASC,Cno DESC)
(2)删除索引
DROP INDEX <索引名>
等值连接
连接运算符为“=”的连接操作称为等值连接,其语法格式为:
[<表名1>.]<列名1> = [<表名2>.]<列名2>
例:查询每个学生及其选修课程的情况。
SELECT Student.*,SC.* FROM Student,SC
WHERE Student.Sno = SC.Sno
例:查询每一门课的间接先修课(即先修课的先修课)
SELECT FIRST.Cno,FIRST.Cname,SECOND.CPre_Cno
FROM Course FIRST,Course SECOND
WHERE FIRST.Pre_Cno
SELECT Student.Sno,Sname,Sex,SBirthDay,
Sdept,Cno,Score
FROM Student
LEFT JOIN SC ON Student.Sno = SC.Sno
以上的左连接也可以用如下的右连接操作代替。
SELECT Student.Sno,Sname,Sex,SBirthDay,Sdept,
Cno,Score
FROM SC
RIGHT JOIN Student ON SC.Sno = Student.Sno
1. 字符串函数
ASCII()函数:返回字符表达式最左端字符的ASCII 码值。
CHAR()函数:用于将ASCII码转换为字符。如果没有输入0-255之间的ASCII码值,则返回一个NULL值。
LOWER()函数:将字符串全部转换为小写。
UPPER()函数:将字符串全部转换为大写。
STR()函数:将数值型数据转换为字符型数据。
LTRIM()函数:将字符串头部的空格去掉。
RTRIM()函数:将字符串尾部的空格去掉。
LEFT()函数:返回从字符串左边开始的指定个数的字符。
RIGHT()函数:返回从字符串右边开始的指定个数的字符。
SUBSTRING()函数:返回字符串表达式的一部分。
2.日期函数
GETDATE()函数:以DATETIME的默认格式返回系统当前的日期和时间。
DAY()函数:返回指定日期的天的整数。
MONTH()函数:返回指定日期月份的整数。
YEAR()函数:返回指定日期的年份的整数。
DATEADD( , ,)函数:返回两个日期之间的时间和。
DATEDIFF( , ,)函数:返回两个日期之间的时间间隔。
3.分组函数
常用的聚集函数
在WHERE子句中包含一个形如SELECT-FROM-WHERE的查询块,此查询块称为子查询或嵌套查询,包含子查询的语句称为父查询或外部查询。
嵌套查询可以将一系列简单查询构成复杂查询,增强查询能力。
嵌套查询在执行时由里向外处理,每个子查询是在上一级外部查询处理之前完成,父查询要用到子查询的结果。
不相关子查询:查询条件不依赖于父查询,由里向外逐层处理。即每个子查询在上一级查询处理之前求解,子查询的结果用于建立其父查询的查找条件。
相关子查询:查询条件依赖于父查询,首先取外层查询中表的第一个元组,根据它与内层查询相关的属性值处理内层查询,若WHERE子句返回值为真,则取此元组放入结果表,然后再取外层表的下一个元组。重复这一过程,直至外层表全部检查完为止。
当用户能确切知道子查询返回单值时,可用比较运算符(=, >, <, >=, <=, !=)连接父查询与子查询。
使用比较运算符的嵌套查询
例:找出和学号“S04”的学生同一系的所有学生。
SELECT * FROM Student
WHERE Sdept=
(SELECT Sdept FROM Student
WHERE Sno=‘ S04’)
使用ANY或ALL操作符的嵌套查询
使用[NOT]EXISTS操作符的嵌套查询
[NOT]EXISTS谓词相当于存在量词“ ”。
带有EXISTS谓词的子查询不返回任何数据,只产生逻辑值真(True)或逻辑值假(False),即若内层子查询结果非空则返回真值,否则返回假值。
例:查询选修了所有课程的学生姓名和所在系。
由于没有全称量词,可将题目的意思转化为等价为:查询这样的学生,没有一门功课是他不选修的。
SELECT Sname, Sdept FROM Student
WHERE NOT EXISTS(
SELECT * FROM Course WHERE NOT EXISTS (
SELECT * FROM SC
WHERE Sno = Student.Sno AND Cno = Course.Cno))
例:查询自动化系的学生及年龄不大于19岁的学生。
SELECT * FROM Student WHERE Sdept= ‘自动化’
UNION
SELECT * FROM Student
WHERE (YEAR(GETDATE())-YEAR(SBirthDay))<=19
- 数据更新
1.插入数据
插入一行新记录,语法格式为:
INSERT INTO <表名> [(<属性列1 >[,<属性列2 >…])]
VALUES(<值1>[,<值2>…])
其中:
<表名>是指要插入新记录的表。
<列名>是可选项,指定待添加数据的列。
VALUES子句指定待添加数据的具体值。
该命令的功能是增加一个新元组,并将“值1”赋值给“属性列1”,“值2”赋值给“属性列2”,以此类推。INTO子句中没有出现的属性列,其新元组在这些列上取空值。
2.插入子查询结果集
利用子查询进行数据的插入,主要用于表间数据的拷贝,即从基本表中提取某些数据插入到另一表中,其语法格式为:
INSERT INTO <表名> [(<列名1>[,<列名2>…])] 子查询
3.修改数据
SQL语言可以使用UPDATE语句对表中的一行或多行记录的某些列值进行修改,其语法格式为:
UPDATE <表名>
SET <列名>=<表达式> [,<列名>=<表达式>]…
[WHERE <条件>]
其中:<表名>是指要修改的表;SET子句给出要修改的列及其修改后的值;WHERE子句指定待修改的记录应当满足的条件,WHERE子句省略时,则修改表中的所有记录。
4.用子查询的结果来修改数据
例:把所有教师的工资提高到平均工资的1.2倍。
UPDATE Teacher SET Salary =
( SELECT 1.2*AVG(Salary) FROM Teacher)
5.用子查询选择要修改的行
例:将计算机系所有学生的成绩置零。
UPDATE SC SET Score = 0
WHERE Sno IN ( SELECT Sno FROM Student
WHERE Sdept = ‘计算机’)
6.用子查询选择删除的行
例:删除刘华的选课记录。
DELETE FROM SC
WHERE Sno =
(SELECT Sno FROM Student
WHERE Sname =‘刘华’)
视图是虚表,其数据不存储,其记录来自基本表,只在数据库中存储其定义。通过视图看到的数据是基本表的数据。
视图在概念上与基本表等同,用户可以在视图上再定义视图,可以对视图进行查询.删除.更新等操作。
定义视图:定义视图使用语句CREATE VIEW,其语法格式为:
CREATE VIEW <视图名>[(<视图列表>)]
AS <子查询>
其中,<视图列表>为可选项,省略时,视图的列名由子查询的结果决定。
组成视图的属性列名要么全部省略,要么全部指定。
如果视图定义中省略了属性列名,则该视图的属性列名由子查询中SELECT子句的目标列组成。但是下列三种情况下必须明确指定组成视图的所有列名:
1)某个视图的属性列不是单纯的属性名,而是聚集函数或列表达式。
2)多表连接导出的视图中有几个同名列作为该视图的属性列名。
3)需要在视图中为某个列启用新的更合适的名字。
在子查询中不许使用ORDER BY 子句和DISTINCT短语,如果需要排序,则可在视图定义后,对视图查询时再进行排序。
例:创建一个计算机系学生情况的视图SUB_S。
CREATE VIEW SUB_S AS
SELECT Sno,Sname,SbirthDay
FROM Student WHERE Sdept =‘计算机’
其中:视图名字为SUB_S,省略了视图列表,视图由子查询中的
列Sno,Sname,SBirthDay组成。
视图的查询,数据更新,删除操作都和基本表的一致
例:把对Student表和Course表的全部操作权限权限授予zhao,
并允许zhao将该权限授予他人。
GRANT ALL PRIVILEGES ON Student,Course
TO zhao WITH GRANT OPTION26
REVOKE <权限>[,<权限>]…[ ON <对象类型>
<对象名>] FROM <用户>[,<用户>]…
例:把用户zhao修改成绩的权限收回。
REVOKE UPDATE (Score) ON SC FROM zhao
DENY ALL [Privileges] | <权限组> [ON <对象名>]
TO <用户组> | PUBLIC
其中,ON子句用于说明对象特权的对象名。对象名指的是表名、视图名、视图和表的字段或者存储过程名。如果使用DENY语句禁止用户获得某个权限,那么以后将该用户添加到已得到该权限的组或角色时,该用户不能访问这个权限。
存储过程是利用T-SQL编写的一组规定的操作。在调用一个存储过程时,它执行所包含的操作。此过程存储在数据库中。
. 定义存储过程
用户在数据库中建立存储过程,其语法格式为:
CREATE PROCEDURE procedure_name
[@parameter data_type][OUTPUT]
[ ,...n ]
[WITH]{RECOMPILE|ENCRYPTION}
AS
SQL_statement
GO
各参数说明如下:
procedure_name:是用户定义的存储过程名称,符合SQL Server标识符定义的规则,一般长度不超过128个字符。在一个数据库中或对其所有者而言,存储过程的名字必须唯一。
@parameter:是存储过程的参数,要求每个参数名前要有一个“@”符号,且该参数仅为该程序内部使用。
data_type:是参数的数据类型。在存储过程中,所有的数据类型包括TEXT和IMAGE都可被用作参数,但是游标数据类型只能被用作OUTPUT参数。
OUTPUT:表明该参数是一个返回参数,用OUTPUT参数可以向调用者返回信息,TEXT类型的参数不能用作OUTPUT参数。
[WITH]{RECOMPILE|ENCRYPTION}:其中,RECOMPILE表示每次执行此存储过程时都重新编译一次。ENCRYPTION表示所创建的存储过程的内容会被加密。
例:编写一个存储过程,实现删除一个学生的记录。由于一个学生可能已经选课,所以在删除一个学生的数据前,必须首先删除该学生选课数据,然后再删除学生数据。
CREATE PROCEDURE usp_DeleteAStudent
@Sno char(5), @Sname varchar(8) OUTPUT
AS
IF EXISTS (SELECT * FROM SC WHERE Sno = @Sno)
DELETE FROM SC WHERE Sno = @Sno
SELECT @Sname = Sname FROM Student
WHERE Sno = @Sno
DELETE FROM Student WHERE Sno = @Sno
GO
存储过程创建完成后,用户可以通过调用存储过程达到执行其中SQL语句的目的。
例:执行上例定义的存储过程,并删除学号为“95010”的相关信息。
– 测试和运行存储过程
DECLARE @Sname VARCHAR(8)
– 调用存储过程
EXECUTE usp_DeleteAStudent ‘95010’, @Sanme
OUTPUT
– 显示返回变量值
SELECT @Sname
删除存储过程:用户也可以删除已经创建好的存储过程,其语法格式为:
DROP PROCEDURE usp_DeleteAStudent;
GO
语句执行后,将从数据库中已建立的存储过程“usp_DeleteAStudent”删除掉。
触发器是一种用来保障参照完整性的特殊的存储过程,它维护不同表中数据间关系的有关规则。
定义触发器的语法:
CREATE TRIGGER[OWNER.] trigger_name
ON [OWNER.] { TABLE | VIEW }
FOR { [ INSERT ] [ , ] [ UPDATE ] [ ,] [ DELETE] } AS SQL_statement
trigger_name:是触发器的名称。在数据库中必须唯一。
TABLE | VIEW:是在其上执行触发器的表或视图,有时称为触发器表或触发器视图。可以选择是否指定表或视图的所有者名称。
[INSERT] [ , ] [UPDATE] [ ,] [DELETE]:是指定在表或视图上执行哪些数据修改语句时将激活触发器的关键字。在触发器定义中允许使用以任意顺序组合的这些关键字,但必须至少指定一个选项,如果指定的选项多于一个,则需要用逗号分隔这些选项。
AS:是触发器将要执行的操作。
触发器是针对表一级的,这就意味着,只有表的所有者拥有创建触发器的权利。当对指定的表进行某种特定操作(如INSERT、UPDATE或DELETE)时,触发器产生作用。针对数据表的三种操作,有三种类型的触发器
1)INSERT触发器: 当向数据表中插入数据时,INSERT触发器自动执行。INSERT触发器会自动建立一个Inserted临时表,新增加到触发器表中的记录同时会增加到Inserted表中。
2)DELETE触发器 当向数据表中删除数据时,DELETE触发器自动执行。DELETE触发器会自动建立一个Deleted临时表,从触发器表中删除的记录同时会增加到Deleted表中。
3)UPDATE触发器 当修改数据表中数据时,UPDATE触发器自动执行。UPDATE触发器会自动建立一个Inserted表和一个Deleted表,修改记录就等于插入记录和删除记录。新增加到触发器表中的记录(新记录)同时会增加到Inserted表中,从触发器表中删除的记录(旧记录)同时会增加到Deleted表中
在使用触发器过程中,注意如下限制:
1)一个表最多只能有三个触发器,INSERT、UPDATE或DELETE。
2)每个触发器只能用于一个表。
3)不能对临时表创建触发器。
4)不能将触发器用于系统表。
例4-72利用触发器来保证学生-课程库中SC表的参照完整性,以维护其外码与参照表中的主码数据的一致性。
例4-72中,在选课基本表SC上定义了INSERT触发器:SC_inserted。
该触发器定义后,当使用INSERT语句向选课基本表SC进行数据录入时,就会调用触发器SC_inserted
此时,若条件(SELECT COUNT(*) FROM Student,inserted,Course WHERE Student.Sno = inserted.Sno AND inserted.Cno = Course.Cno)=0成立,说明不满足该表的参照完整性约束条件,则启用事务回滚机制,拒绝向选课基本表插入数据;若该条件不成立,则接受向选课基本表插入数据。
即:向SC表录入的新数据中,Sno字段的数据在Student基本表中已存在,且Cno字段的数据在Course基本表中已存在,则该条新数据能够成功插入SC基本表中,否则启用事务回滚机制,拒绝向SC基本表插入数据。
例4-73在学生基本表Student上定义UPDATE触发器,要求:若更改学生基本表Student的学号信息,则需要在选课基本表SC中也同时更改该学生的学号信息。
其中,Deleted表示触发事件表中“旧的一条记录”,Inserted表示触发事件表中“新的一条记录”。一个Update 的过程可以看作:生成新的记录到Inserted表,复制旧的记录到Deleted表,然后删除Student记录并写入新纪录。
该触发器成功创建后,当更新Student基本表中Sno字段的内容时,会同步更新SC基本表中相应Sno字段的数据,从而进一步保证了数据的一致性。
例4-74在学生基本表Student上定义Delete触发器,要求:若删除学生基本表Student的学号信息,则需要在选课基本表SC中也同时删除该学生所有的选课信息。
该触发器成功创建后,当删除Student基本表中的记录时,会同步删除SC基本表中满足(SC.Sno = Student.Sno)条件的记录,从而进一步保证了数据的一致性。
从上述三个例子中,可以看出使用触发器的关键,分别是触发机制以及Deleted和Inserted临时表的应用。