终于开始实战了,首先我这里是下载的SQL server,因为oracle和SQLserver的部分语法不同,所以本文出现的代码可能在oracle中报错
一、了解SQL语言的特色
SQL的特点
综合统一:SQL语言集数据定义语言DDL、数据操纵语言DML、数据控制语言DCL的功能于一体。
高度非过程化:非关系数据模型的数据操纵语言是面向过程的语言,操作必须指明存取路径;而用SQL语言进行数据操作,只要提出“做什么”,无须指明“怎么做”,因此无需了解存取路径。
面向集合的操作方式:非关系数据模型采用的是面向记录的操作方式,操作对象是一条记录;而SQL语言采用的集合操作方式,不仅操作对象、查询结果可以是元组的集合,而且一次插入、删除、更新操作的对象也可以是元组的集合。
以同一种语法结构提供两种使用方法:SQL语言既是自含式语言,能独立地用于联机交互;又是嵌入式语言,能嵌入到高级语言中进行混合编程。
语言简洁,易学易用,完成核心功能只用9个动词
二、具体操作
1、定义、修改与删除基本表
** 定义基本表**
CREATE TABLE <表名>
(<列名> <数据类型>[ <列级完整性约束条件> ]
[,<列名> <数据类型>[ <列级完整性约束条件>] ] …
[,<表级完整性约束条件> ] );
其中:表名为所要定义的基本表的名字,列名为组成该表的各个属性(列),列级完整性约束条件为涉及相应属性列的完整性约束条件,表级完整性约束条件为涉及一个或多个属性列的完整性约束条件。常用的完整性约束有:主码约束PRIMARY KEY、唯一性约束UNIQUE、非空值约束NOT NULL、参照完整性约束FOREIGN KEY REFERENCES。
例1:建立一个“学生”表Student,它由学号Sno、姓名Sname、性别Ssex、年龄Sage、系别Sdept五个属性组成。其中学号不能为空,值是唯一的,并且姓名取值也唯一
create table Student1(Sno char(5) not null unique,Sname char(20) unique,Ssex char(1),Sage int,Sdept char(15)
)
修改基本表
ALTER TABLE <表名>
[ ADD <新列名> <数据类型> [ 完整性约束 ] ]
[ DROP <完整性约束名> ] [ DROP column <列名> ]
[ MODIFY <列名> <数据类型> ];
其中:表名为要修改的基本表,ADD子句为增加新列和新的完整性约束条件,DROP子句为删除指定的完整性约束条件,MODIFY子句为用于修改列名和数据类型。
例2:向Student表增加“入学时间”列,其数据类型为日期型。
ALTER TABLE Student ADD Scome DATE;
不论基本表中原来是否已有数据,新增加的列一律为空值。
例3:将年龄的数据类型改为半字长整数。
ALTER TABLE Student MODIFY Sage SMALLINT;
修改原有的列定义有可能会破坏已有数据。
例4:删除学生姓名必须取唯一值的约束。
ALTER TABLE Student DROP UNIQUE(Sname);
SQL没有提供删除属性列的语句,用户只能间接实现这一功能:先把表中要保留的列及其内容复制到一个新表中,然后删除原表,再将新表重命名为原表名。但有的DBMS提供直接删除属性列的语句,如:ALTER TABLE Student Drop Scome;
删除基本表
DROP TABLE <表名>;
基本表定义一旦删除,表中的数据、表上建立的索引和视图都将自动删除。但Oracle中删除基本表后建立在此表上的视图仍保留在数据字典中,但用户引用时就出错。
例5:删除Student表。
DROP TABLE Student ;
建立与删除索引
建立索引是加快查询速度的有效手段,建立与删除索引由DBA或表的属主负责完成,但有些DBMS自动建立PRIMARY或KEY UNIQUE列上的索引。
2、数据类型
数值型数据
1.Bigint
Bigint型数据可以存放从-263到263-1范围内的整型数据。以bigint数据类型存储的每个值占用8个字节,共64位,其中63位用于存储数字,1位用于表示正负。
2.Int
Int也可以写作integer,可以存储从-231231-1(-2,147,483,6482,147,483,647)范围内的全部整数。以int数据类型存储的每个值占用4个字节,共32位,其中31位用于存储数字,1位用于表示正负的区别。
3.smallint
Smallint型数据可以存储从-215~215- 1(-32,768~32,767)范围内的所有整数。以smallint数据类型存储的每个值占用2个字节,共16位,其中15位用于存储数字,1位用于表示正负的区别。
4.Tinyint
Tinyint型数据可以存储0~255范围内的所有整数。以tinyint数据类型存储的每个值占用1个字节。
整数型数据可以在较少的字节里存储较大的精确数字,而且存储结构的效率很高,所以平时在选用数据类型时,尽量选用整数数据类型。
5.Decimal和Numeric
事实上,numeric数据类型是decimal数据类型的同义词。但是二者也有区别,在表格中,只有numeric型数据的列可以带有identity关键字,decimal可以简写为dec。
使用decimal和numeric型数据可以精确指定小数点两边的总位数(精度,precision简写为p)和小数点右面的位数(刻度,scale简写为s)。
在SQL Server中,decimal和numeric型数据的最高精度的可以达到38位,即1≤p≤38,0≤s≤p。decimal和numeric型数据的刻度的取值范围必须小于精度的最大范围,也就是说必须在-1038-1~1038-1之间。
SQL Server分配给decimal和numeric型数据的存储空间随精度的不同而不同,一般说来对应的比例关系如下所示:
精度范围 分配字节数
1~9 5
10~19 9
20~28 13
29~38 17
6.float和real
Real型数据范围从-3.40E+38~1.79E+38,存储时使用4个字节。精度可以达到7位。
float型数据范围从-1.79E+381.79E+38。利用float来表明变量和表列时可以指定用来存储按科学计数法记录的数据尾数的bit数。如float(n),n的范围是153。当n的取值为124时,float型数据可以达到的精度是7位,用4个字节来存储。当n的取值范围是2553时,float型数据可以达到的精度是15位,用8个字节来存储。
字符数据类型
1.Char
利用Char数据类型存储数据时,每个字符占用一个字节的存储空间。Char数据类型使用固定长度来存储字符,最长可以容纳8000个字符。利用Char数据类型来定义表列或者定义变量时,应该给定数据的最大长度。如果实际数据的字符长度短于给定的最大长度,则多余的字节会用空格填充。如果实际数据的字符长度超过了给定的最大长度,则超过的字符将会被截断。在使用字符型常量为字符数据类型赋值时,必须使用单引号(‘’)将字符型常量括起来。
2.Varchar
Varchar数据类型的使用方式与Char数据类型类似。SQL Server 利用Varchar数据类型来存储最长可以达到8000字符的变长字符。与Char 数据类型不同,Varchar数据类型的存储空间随存储在表列中的每一个数据的字符数的不同而变化。
例如,定义表列为Varchar(20),那么存储在该列的数据最多可以长达20个字节。但是在数据没有达到20个字节时并不会在多余的字节上填充空格。
当存储在列中的数据的值大小经常变化时,使用Varchar数据类型可以有效地节省空间
3.Text
当要存储的字符型数据非常庞大以至于8000字节完全不够用时,Char和Varchar数据类型都失去了作用。这时应该选择Text数据类型。
Text数据类型专门用于存储数量庞大的变长字符数据。最大长度可以达到231-1个字符,约2GB。
下面的例子建立一个以字符类型定义的表,然后向其中插入了一行数。
创建一个表格:
create table chars_example
(char_1 char(5), varchar_1 varchar(5), text_1 text)
go
插入一行数据:
insert into chars_example values(“abcd”,“abc”,“dddddddddddddddddddddddddd”)
go
日期/时间数据类型
==1.Datetime ==
Datetime数据类型范围从1753年1月1日到9999年12月31日,可以精确到千分之一秒。Datetime数据类型的数据占用8个字节的存储空间。
2.Smalldatetime
Smalldatetime数据范围从1900年1月1日到2079年6月6日,可以精确到分。Smalldatetime数据类型占4个字节的存储空间。
SQL Server在用户没有指定小时以上精度的数据时,会自动设置Datetime和Smalldatetime数据的时间为00:00:00。
货币数据类型
1.Money
Money数据类型存储的货币值由2个4字节整数构成。前面的一个4字节表示货币值的整数部分,后面的一个4字节表示货币值的小数部分。以Money存储的货币值的范围从-263~263-1,可以精确到万分之一货币单位。
2.Smallmoney
由Smallmoney数据类型存储的货币值由2个2字节整数构成。前面的一个2字节表示货币值的整数部分,后面的一个2字节表示货币值的小数部分。以Smallmoney存储的货币值的范围从-214,748.3648~+214,748.3647,也可以精确到万分之一货币单位。
在把值加入定义为Money或Smallmoney数据类型的表列时,应该在最高位之前放一个货币符号$或其他货币单位的符号,但是也没有严格要求。
例如:
create table number_example2 (money_num money, smallmoney_num smallmoney,)
go
插入1行数据:
INSERT INTO number_example2 VALUES ($222.222,$333.333)
二进制数据类型
所谓二进制数据是一些用十六进制来表示的数据。例如,十进制数据245表示成十六进制数据就应该是F5。在SQL Server中,共使用了3种数据类型来存储二进制数据,分别是binary,varbinary 和Image。
二进制数据类型同字符型数据类型非常相似。使用binary数据类型定义的列或变量,具有固定的长度,最大长度可以达到8K字节;使用varbinary数据类型定义的列或变量具有不固定的长度,其最大长度也不得超过8K字节;Image数据类型可用于存储字节数超过8K字节的数据,比如Microsoft Word文档、Microsoft Excel图表以及图像数据(包括.GIF、.BMP文件)等。
一般说来,最好使用binary或 varbinary数据类型来存储二进制数据。只有在数据的字节数超过了8KB的情况下,才使用Image数据类型。
在对二进制数据进行插入操作时,无需在数据上加上“”,但须在数据常量前面增加一个前缀0x。
例如:
create table binary_example (bin_1 binary (5), bin_2 varbinary(5))
go
输入数据:
insert into binary_example values (0xaabbccdd,0xaabbccddee)
insert into binary_example values (0xaabbccdde,0x)
go
双字节数据类型
1.Nchar(n)
Nchar(n)是固定长度的双字节数据类型,括号里的n用来定义数据的最大长度。n的取值范围是1~4000,所以使用Nchar数据类型所能存储的最大字符数是4000字符。由于存储的都是双字节字符,所以双字节数据的存储空间为:字符数*2(字节)。
Nchar数据类型的其他属性及使用方法与Char数据类型一样。例如,也在有多余字节的情况下会自动加上空格进行填充。
2.Nvarchar(n)
Nvarchar(n)数据类型存储可变长度的双字节数据类型,括号里的n用来定义数据的最大长度。n的取值为0~4000,所以使用Nvarchar数据类型所能存储的最大字符数也是4000。Nvarchar数据类型的其他属性及使用方法与Varchar数据类型一样。
3.Ntext(n)
Ntext数据类型存储的是可变长度的双字节字符,Ntext数据类型突破了前2种双字节数据类型不能超过4000字符的规定,最多可以存储多达230-1个双字节字符。Ntext数据类型的其他属性及使用方法与Text数据类型一致。
查询
查询语句格式:
SELECT [ALL|DISTINCT] <目标列表达式> [,<目标列表达式>] …
FROM <表名或视图名>[, <表名或视图名> ] …
[ WHERE <条件表达式> ]
[ GROUP BY <列名1> [ HAVING <条件表达式> ] ]
[ ORDER BY <列名2> [ ASC|DESC ] ];
其中:SELECT子句指定要显示的属性列;FROM子句指定查询对象(基本表或视图);WHERE子句指定查询条件;GROUP BY子句对查询结果按指定列的值分组,该属性列值相等的元组为一个组,通常会在每组中作用集函数;HAVING短语筛选出只有满足指定条件的组;ORDER BY子句对查询结果表按指定列值的升序或降序排序。
单表查询:查询仅涉及一个表,是一种最简单的查询操作。
查询指定列或全部列
例1:查询全体学生的学号与姓名。
SELECT Sno,Sname FROM SStudent;
例2:查询全体学生的姓名、学号、所在系。
SELECT Sname,Sno,Sdept FROM Sstudent;
例3:查询全体学生的详细记录。
SELECT Sno,Sname,Ssex,Sage,Sdept
FROM SStudent;或者SELECT * FROM SStudent;
查询经过计算的值:SELECT子句的<目标列表达式>为算术表达式、字符串常量、函数、列别名等 。
例4: 查全体学生的姓名及其出生年份。
SELECT Sname,2022-Sage FROM SStudent;
SELECT Sname,year(getadate)-Sage FROM SStudent;
输出结果: Sname 2022-Sage
--------- -------------
李勇 2003
刘晨 2004
王名 2005
张立 2006
例5:查询全体学生的姓名、出生年份和所有系,要求用小写字母表示所有系名。
SELECT Sname,'Year of Birth:',2021-Sage,LOWER(Sdept) FROM SStudent;
输出结果:
Sname ‘Year of Birth:’ 2021-Sage ISLOWER(Sdept)
------- ---------------- --------- --------------
李勇 Year of Birth: 2003 cs
刘晨 Year of Birth: 2004 is
王名 Year of Birth: 2005 ma
张立 Year of Birth: 2006 is
可以使用列别名改变查询结果的列标题
SELECT Sname NAME,'Year of Birth:' BIRTH, 2019-Sage BIRTHDAY,LOWER(Sdept) DEPARTMENT FROM sStudent;
选择表中的若干元组:在WHERE子句中设置查询条件。
消除取值重复的行:在SELECT子句中使用DISTINCT短语
例6:查询选修了课程的学生学号。
SELECT Sno FROM SC; 或 SELECT ALL Sno FROM SC;
SELECT DISTINCT Sno FROM SC;
ALL的结果: Sno DISTINCT的结果: Sno
------- -------
21001 21001
21001 21002
21001
21002
21002
DISTINCT短语的作用范围是所有目标列
例:查询选修课程的各种成绩。
错误的写法
SELECT DISTINCT Cno,DISTINCT Grade FROM SC;
正确的写法
select distinct cno, grade from sc
确定大小:在WHERE子句的<比较条件>中使用比较运算符。
例8:查询所有年龄在20岁以下的学生姓名及其年龄。
SELECT Sname,Sage FROM SStudent WHERE Sage < 20;或SELECT Sname,Sage FROM SStudent WHERE NOT Sage >= 20;
确定范围:在WHERE子句的<比较条件>中使用谓词BETWEEN… AND或NOT BETWEEN … AND
例9:查询年龄在20~23岁(包括20岁和23岁)间的学生的姓名、系别和年龄。
SELECT Sname,Sdept,Sage FROM SStudent
WHERE Sage BETWEEN 20 AND 23;
例10:查询年龄不在20~23岁之间的学生姓名、系别和年龄。
SELECT Sname,Sdept,Sage FROM SStudent
WHERE Sage NOT BETWEEN 20 AND 23;
确定集合:在WHERE子句的<比较条件>中使用用谓词IN(值表)或NOT IN (值表),(值表)是用逗号分隔的一组取值。
例11:查询信息系、数学系和计 算机系学生的姓名和性别。
SELECT Sname,Ssex FROM SStudent
WHERE Sdept IN ( 'IS','MA','CS' );
例12:查询既不是信息系、数学系,也不是计算机系的学生的姓名和性别。
SELECT Sname,Ssex FROM SStudent
WHERE Sdept NOT IN ( 'IS','MA','CS' );
例13:查询学号为95001的学生的详细情况。
SELECT * FROM SStudent WHERE Sno LIKE '95001';
等价于:SELECT * FROM SStudent WHERE Sno = ‘95001’;
例14:查询所有姓刘学生的姓名、学号和性别。
SELECT Sname,Sno,Ssex FROM SStudent
WHERE Sname LIKE '刘%';
例15:查询姓“欧阳”且全名为三个汉字的学生的姓名。
SELECT Sname FROM SStudent WHERE Sname LIKE '欧阳__';
例16:查询名字中第2个字为“阳”字的学生的姓名和学号。
SELECT Sname,Sno FROM SStudent WHERE Sname LIKE '__阳%';
例17:查询所有不姓刘的学生姓名。
SELECT Sname,Sno,Ssex FROM SStudent
WHERE Sname NOT LIKE '刘%';
使用换码字符将通配符转义为普通字符 。
例18:查询DB_Design课程的课程号和学分。
SELECT Cno,Ccredit FROM SCourse
WHERE Cname LIKE 'DB\_Design' ESCAPE '\';
例19:询以DB_开头、且倒数第3个字符为 i的课程的详细情况。
SELECT * FROM SCourse
WHERE Cname LIKE 'DB\_%i__' ESCAPE '\';
涉及空值的查询:在WHERE子句的<比较条件>中使用谓词IS NULL 或 IS NOT NULL,注意IS NULL 不能用= NULL 代替。
例20:某些学生选修课程后没有参加考试,所以有选课记录但没有考试成绩。查询缺少成绩的学生的学号和相应的课程号。
SELECT Sno,Cno FROM SC WHERE Grade IS NULL;
例21:查所有有成绩的学生学号和课程号。
SELECT Sno,Cno FROM SC WHERE Grade IS NOT NULL;
多重条件查询:在WHERE子句的<比较条件>中使用逻辑运算符AND和 OR来联结多个查询条件, AND的优先级高于OR, 可用括号改变优先级。
例22:查询计算机系年龄在20岁以下的学生姓名。
SELECT Sname FROM SStudent
WHERE Sdept= 'CS' AND Sage<20;
例23:查询信息系、数学系和计算机系学生的姓名和性别
SELECT Sname,Ssex FROM SStudent
WHERE Sdept IN ( 'IS','MA','CS' )
可改写为:SELECT Sname,Ssex FROM SStudent
WHERE Sdept= 'IS' OR Sdept='MA' OR Sdept='CS';
例24:查询年龄在20~23岁(包括20岁和23岁)之间的学生的姓名、系别和年龄
SELECT Sname,Sdept,Sage FROM SStudent
WHERE Sage BETWEEN 20 AND 23;可改写为: SELECT Sname,Sdept,Sage
FROM SStudent WHERE Sage>=20 AND Sage<=23;
对查询结果排序:使用ORDER BY子句, 可以按一个或多个属性列排序, 升序ASC,降序DESC,缺省值为升序。当排序列含空值时,ASC排序列为空值的元组最后显示,DESC排序列为空值的元组最先显示。
例25:查询选修了3号课程的学生的学号及成绩,查询结果按分数降序排列。
SELECT Sno,Grade FROM SC
WHERE Cno= '3' ORDER BY Grade DESC;
查询结果 Sno Grade------- -------2101021001 8821002 80
例26:查询全体学生情况,结果按所在系的系号升序排列,同一系中的学生按年龄降序排列。
SELECT * FROM SStudent ORDER BY Sdept,Sage DESC;
使用集函数: 5类主要集函数
计数:COUNT([DISTINCT|ALL] *)
COUNT([DISTINCT|ALL] <列名>)
计算总和:SUM([DISTINCT|ALL] <列名>)
计算平均值:AVG([DISTINCT|ALL] <列名>)
求最大值:MAX([DISTINCT|ALL] <列名>)
求最小值:MIN([DISTINCT|ALL] <列名>)
其中:DISTINCT短语在计算时要取消指定列中的重复值,ALL短语不取消重复值,ALL为缺省值。
例27:查询学生总人数。
SELECT COUNT(*) FROM SStudent;
例28:查询选修了课程的学生人数。
SELECT COUNT(DISTINCT Sno) FROM SC;
注:用DISTINCT以避免重复计算学生人数。
例29:计算1号课程的学生平均成绩。
SELECT AVG(Grade) FROM SC WHERE Cno='1';
例30:查询选修1号课程的学生最高分数。
SELECT MAX(Grade) FROM SC WHERE Cno='1';
对查询结果分组: GROUP BY子句的作用对象是查询的中间结果表,分组方法是按指定一列或多列值分组,值相等的为一组。使用GROUP BY子句后,SELECT子句的列名列表中只能出现分组属性和集函数。使用GROUP BY子句分组细化集函数的作用对象,未对查询结果分组,集函数将作用于整个查询结果;对查询结果分组后,集函数将分别作用于每个组。
例31:求各个课程号及相应的选课人数。
SELECT Cno,COUNT(Sno) FROM SC GROUP BY Cno;
结果 Cno COUNT(Sno)
1 22
2 34
3 44
4 33
5 48
**
使用HAVING短语筛选最终输出结果**:只有满足HAVING短语指定条件的组才输出,HAVING短语与WHERE子句的区别是WHERE子句作用于基表或视图,从中选择满足条件的元组;HAVING短语作用于组,从中选择满足条件的组。
例32:查询选修了3门以上课程的学生学号。
SELECT Sno FROM SC GROUP BY Sno
HAVING COUNT(*) >3;
查询有3门以上课程是90分以上的学生的学号及课程数。
SELECT Sno, COUNT(*) FROM SC WHERE Grade>=90 GROUP BY Sno HAVING COUNT(*)>=3;