初学SQL Server的基本操作和使用,每一种操作均可以在Microsoft SQL Server Management Studio中进行,也可以使用SQL脚本进行。本笔记主要记录脚本的具体操作方式。
创建的关键词为create。
create database testdb
on primary (
name ='testdb',
filename='F:\testdb.mdf',
size=10MB,
maxsize=100MB,
filegrowth=5MB
)
log on (
name='testdb_log',
filename='F:\testdb.ldf',
size=10MB,
maxsize=100MB,
filegrowth=5MB
)
第一个代码块是定义数据库的主文件,第二个代码块是定义log日志。
name\filename是名称;size为文件初始的大小;maxsize为文件每次增长的步长。
如上图,在单击运行后,创建数据库成功!
修改的关键词为alter、modify,删除的关键词为drop。
在当前要修改和删除的数据库下,新建查询,输入指令。
esec sp_helpdb testdb //查看testdb数据库的属性。
alter database testdb
modify name=testdb02 //修改数据库的名称
成功将数据库datadb名字修改为datadb02。上述指令只修改了数据库的名称,注意数据库的逻辑文件名称不能修改。只能对它的参数进行改动。
alter database testdb02
modify file(
name='testdb',
size=50MB,
maxsize=100MB,
filegrowth=5MB
);
下面删除数据库的命令,删库跑路警告【手动滑稽保命】。
drop database [testdb02];
数据类型 | 所占内存 | 范围 |
---|---|---|
bigint | 8字节 | -9223372036854775808~9223372036854775807 |
int | 4字节 | -2147483648~2147483647 |
smallint | 2字节 | -32768~23767 |
tinyint | 1字节 | 0~255 |
float | 取决于n的值 |
数据类型 | 输出 |
---|---|
time | 19:13:29.1234567 |
date | 2020-03-13 |
smalldatetime | 2020-03-13 19:14:20 |
datetime | 2020-03-13 19:13:29.123 |
数据类型 | 说明 |
---|---|
char(n) | n必须为1~8000之间的值,是固定长度。 |
varchar(n) | n可以为1~8000之间的值,是可变长度。 |
nchar(n) | 固定长度Unicode字符串数据,n必须为1~4000 |
nvarchar(n) | 可变长度Unicode字符串数据,n必须为1~4000 |
Unicode为双字节编码,可以统一所有语言的编码。每一个字符均占用两个字节。
若要创建表,需要提供表的名称以及该表每个列的名称和数据类型。指出每个列中是否允许空值。
设定一个主键,由表的某一列或者多列组成,注意主键是非空且不可重复的。
create table dbo.users //数据库所有者默认为dbo。
(ID int primary key not null, //新建ID属性,设为主键,非空。
name varchar(10) not null, //新建name属性,非空。
age int null //新建age属性,可为空。
)
alter table dbo.users
alter column name varchar(100)
alter table dbo.users
alter column age float
alter table dbo.users
alter column age float not null
alter table dbo.users
add constraint KID primary key(ID)
exec sp_rename 'users.age','ages','column'
alter table users
add grade varchar(10) not null
drop table users
alter table subsidiary
add constraint FK_user foreign key(SUB_no) references main (MAIN_no)
alter table subsidiary
drop constraint FK_user
数据库字段如下:
course(cno,cname,cpon,ccredit)
sc(sno,cno,score)
student(sno,sname,ssex,sage,sdept,sclass,sbirth,stime)
从sudent表中查询属性为sno和sname的两列
select sno,sname
from student;
*号码表示全部属性
select *
from student;
例如:查询全体学生的姓名以及出生年份。(出生年份使用2020-年龄即可得到)
select sname , 2020-sage
from student
在要查询的属性后面加一个空格,跟上要指定的新列名即可。如下例:
此处的‘year of birth’为常量函数,所以每一行的属性均为‘year of birth’
select sname name,'year of birth'birth,2020-sage birthday
from student
如果没有指定的distinct关键词,则缺省ALL
例如从student表中查询性别并去重:
select distinct ssex
from student
select sname,sno ,sdept
from student
where sdept='软件工程'
select sname,sage
from student
where sage<20
select distinct sno
from sc
where score<60
select sname,sage
from student
where sage not between 20 and 22
select sname,ssex
from student
where sdept in ('软件工程','计算机')
--如果不适用谓词,则可以写成
--where sdept ='软件工程' or sdept= '计算机'
select sname,ssex
from student
where sname like '_元%'
select sname,ssex
from student
where sname like '李__'
select sname,ssex
from student
where sname not like '程%'
select sname,ssex
from student
where sname like '李\_%嘤__' escape'\'
select sname,ssex
from student
where ssex is null
where sdept in ('软件工程','计算机')
如果不适用谓词,则可以写成
where sdept ='软件工程' or sdept= '计算机'
可以按照一个或多个属性列排序,asc为升序,desc为降序。默认的缺省值为升序。
对于空值,排序时显示的次序由具体的系统实现来决定。
例11:查询选修了c1号课程的学生的学号以及成绩,查询结果按照分数降序排列
select sno,score
from sc
where cno='c1'
order by score desc
运行结果如图:
例12:查询全体学生情况,查询结果按照所在系的系号升序排列,同一系中学生按年龄降序排列。
select sdept,sage,ssex
from student
order by sdept asc,sage desc
1 .统计元组个数
语法规则:**count(*)**
例13:查询学生的总人数
select count(*)
from student
语法规则:count (distinct 列名)
例14:查询选修了课程的学生人数
select count(distinct sno)
from sc
运行结果如图:
3. 计算一列值的中和
语法规则:sum (distinct 列名)
例15:查询学生20172018选修课程的总学分数
select sum(ccredit)
from sc,course
where sno='20172018'and sc.cno=course.cno
4 .计算一列值的平均值
语法规则:avg(distinct 列名)
例16:计算c1课程学生的平均成绩
select avg(score)
from sc
where cno='c1'
5 . 求一列中的最大值和最小值
语法规则:max(distinct 列名) 或者是 min(distinct 列名)
例17: 查询选修c1课程学生的最高分数
select max(score)
from sc
where cno='c1'
group by 可以细化聚集函数的作用对象,如果未对查询结果分组,聚集函数将作用于整个查询结果。对查询结果分组后,聚集函数将分别作用于每一个组。
例18:求每个课程号以及相应的选课人数
select cno,count(sno)
from sc
group by cno
select sno
from sc
group by sno
having count(sno)>3
运行结果如图:
例20:查询平均成绩大于等于90分的学生学号和平均成绩
select sno,avg(score)
from sc
group by sno
having avg(score)>=90
总结:
例21:列出软件工程系姓马且名字为两个字的同学的学号和姓名,并按照学号大小排序。
select sno,sname
from student
where sname like '马_'and sdept='软件工程'
order by sno asc
运行结果如图:
例22:按系并区分男女统计各系学生的人数、并按照人数降序排列。
select ssex,sdept,count(sno)
from student
group by ssex,sdept
order by count(sno) desc
等值连接:连接运算符为“=”
select student.*,sc.*
from student,sc
where student.sno=sc.sno
--连接条件为student.sno=sc.sno
运行结果如下:
在上面的运行结果中,student.sno和sc.sno是重复冗余的,为了实现自然连接,可以手动将要展示的列在select语句中写出来,可采用以下代码
select student.sno,sname,ssex,sage,sdept,cno,sclass
from student,sc
where student.sno=sc.sno
select sname,student.sno,score
from student,sc
where student.sno=sc.sno and sc.cno='c2'and score>90
自身连接:一个表与自己进行连接,是一种特殊的连接,需要给表起别名以示区别
由于所有属性名都是同名属性,因此必须使用别名前缀
select first.cname,second.cname
from course first,course second
where first.cpno=second.cno
普通连接操作只输出满足连接条件的元组。外连接操作以指定表为连接主体,将主体表中不满足连接条件的元组一并输出。
左外连接——列出左边关系中所有的元组
右外连接——列出右边关系中所有的元组
select student.sno,sname,ssex,sage,cno
from student
left join sc on
(student.sno=sc.sno);
两个表以上进行连接
select student.sno,student.sname,course.cname,score
from student,sc,course
where student.sno=sc.sno and sc.cno=course.cno
子查询的查询条件不依赖于父查询,由里向外逐层处理。即每个子查询在上一级查询处理之前求解,子查询的结果用于建立其父查询的查找条件。
子查询的查询条件依赖于父查询。
例5:查询与“李元垚”在同一个系学习的学生。
分析:①先确定“李元垚”所在的系名
select sdepy
from student
where sname=‘李元垚’
此段代码运行结果为:‘软件工程’
然后再查询软件工程系的所有学生
select sno,sname,sdept
from student
shere sdept=‘软件工程’
将上述两段代码合二为一,即可得到一个嵌套查询的语句
select sno,sname,sdept
from student
where sdept in
(select sdept
from student
where sname='李元垚')
此查询为不相关子查询,运行结果如图所示:
还可以用自身连接查询来完成
select s1.sno,s1.sname,s1.sdept
from student s1,student s2
where s2.sname='李元垚' and s1.sdept=s2.sdept
不相关子查询可以转换成相关的连接查询。
例6:查询选修了课程名为“数据结构”的学生学号和姓名
分析:①首先在course表中找出‘’“数据结构”课程的课程号
select cno
from course
where cname=‘数据结构’
得到数据结构课程号为‘c3’
②然后在sc表中找出选修了’c3’课程的学生学号
select sno
from sc
where cno=‘c3’
③在student表中取出对应的sno和sname
select sno,sname
from student
where sno in
(select sno
from sc
where cno =
(select cno
from course
where cname='数据结构'))
select student.sno,student.sname
from student,sc,course
where course.cname='数据结构' and
course.cno=sc.cno and
sc.sno=student.sno
当能确切知道内层查询返回单值时,可用比较运算符(> ,< ,= ,>= ,<= ,!= 或< >)。
例7:找出每个学生超过他选修课程平均成绩的课程号
可以用相关子查询的思路来解决
需要找出每一个学生的平均分,再选出比平均分高的课程。
select sno,cno
from sc x
where x.score>=(
select avg(score)
from sc y
where x.sno=y.sno)
相关子查询的代码执行过程:
1、从外层查询中取出sc的一个元组x,将元组x的sno值传入内层循环,执行代码如下:
select avg(score)
from sc y
where y.sno=‘20182182’
2、假设执行上述内层查询,得到结果99,则继续返回执行外层查询。执行代码如下:
select sno,cno
from sc
where score>=99
3、假设上述查询可得到结果(20182182,c1) ,(20182182,c2)
4、按照上面三步再次循环,直到外层查询sc元组全部处理完毕。类似于双层for循环的执行。
在SQL中,采用“谓词”的方式来表达存在量词和全称量词。
表示 | 含义 |
---|---|
> any | 大于子查询结果中的某个值 |
> all | 大于子查询结果中的所有值 |
< any | 小于子查询结果中的某个值 |
> all | 小于子查询结果中的所有值 |
>= any | 大于等于子查询结果中的某个值 |
>= all | 大于等于子查询结果中的所有值 |
<= any | 小于等于子查询结果中的某个值 |
<= all | 小于等于子查询结果中的所有值 |
= any | 等于子查询结果中的某个值 |
= all | 等于子查询结果中的所有值 |
!= any | 不等于子查询结果中的某个值 |
!= all | 不等于子查询结果中的任何一个值 |
例8:查询非软件工程系中比软件工程系中任意一个学生年龄小的学生姓名和年龄
本题中要求非软件工程系学生比软件工程任意一个学生年龄小的学生,因为是“任意”,所以只要比年龄最大的学生小,即可满足题意。所以可使用谓词any或者是聚合函数max。
使用any谓词
select sname,sage
from student
where sage<any (
select sage
from student
where sdept='软件工程')
and sdept!='软件工程'
使用max集合函数
select sname,sage
from student
where sage< (
select max(sage)
from student
where sdept='软件工程')
and sdept!='软件工程'
运行结果相同,如下图:
例8:查询非软件工程系中比软件工程系中所有一个学生年龄小的学生姓名和年龄
本题中要求非软件工程系学生比软件工程所有学生年龄小的学生,因为是“所有”,所以只要比年龄最小的学生小,即可满足题意。所以可使用谓词all或者是聚合函数min。
使用all谓词
select sname,sage
from student
where sage<all(
select sage
from student
where sdept='软件工程')
and sdept!='软件工程'
使用min聚合函数
select sname,sage
from student
where sage<(
select min(sage)
from student
where sdept='软件工程')
and sdept!='软件工程'
通过以上例子可以发现谓词和聚合函数之间具有一定的转换关系。
= | != | < | <= | > | >= | |
---|---|---|---|---|---|---|
any | in | - - | <=max |
>min |
>=min |
|
all | - - | not in | <=min |
>max |
>=max |
|
例9:查询所有选修了c1课程的学生姓名
用相关子查询的思路来解决这个问题,查询涉及sc关系和student关系。
1、在student表中依次取出每个元组的sno值,用于检测sc中是否存在。
2、若存在且cno=‘c1’,则取出sname,并送入结果表。
select sname
from student
where exists (
select *
from sc
where student.sno=sc.sno and cno='c1')
例10:查询"李元垚"在同一个系学习的学生(exists替换版本)
select sname,sno,sdept
from student a
where exists(
select*
from student b
where a.sdept=b.sdept and b.sname='李元垚')
运行结果如下:
例10:查询选修了全部课程的学生姓名。
not exists的用法:
若内层查询结果非空,则外层的where子句返回假值;
若内层查询结果为空,则外层的where子句返回真值;
最后将真值的sname显示出来。
假设一个同学选修了全部课程:内层循环因为能找到记录,所以返回假值。外层循环中因为子句的where为假值(即记录不存在),所以返回外层循环返回真值。每一门课程都不可以输出时,这个学号对应的元组才可以输出。表示这个学生选修了全部的课程。
假设一个同学有一门课程没选:内层循环会有一个值返回真值。所以外层循环会返回假的值,所以该同学的姓名不予显示。
select sname
from student
where not exists(
select *
from course
where not exists(
select *
from sc
where sno=student.sno and cno=course.cno))
例11:查询至少选修了学生20182182选修的全部课程的学生学号。
用逻辑蕴涵表达式来表达该查询。
p:“学生20182182选修了课程y”
q:“学生x选修了课程y”
则可以表示为 任意p—>q
经过逻辑演算,可变为:不存在y(p∧¬q)
即:不存在这样的课程y,学生20182182选修了y,而学生x没有选。
并操作:union
交操作:intrsect
差操作:except
参加集合操作的各查询结果的列数必须相同,对应项的数据类型也必须相同。
例12:查询软件工程系学生和年龄不大于19岁的学生。
select sname,sno,sdept,sage
from student
where sdept='软件工程'
union
select sname,sno,sdept,sage
from student
where sage<=19
select sname,sno,sdept,sage
from student
where sdept='软件工程'
intersect
select sname,sno,sdept,sage
from student
where sage<=19
select sname,sno,sdept,sage
from student
where sdept='软件工程'
except
select sname,sno,sdept,sage
from student
where sage<=19
select [all/distinct] <列表表达式> [别名]
from <表名或视图名> [别名]
join <表名> on <连接条件>
where <条件表达式>
group by <列名>
having <条件表达式>
order by <列名>
使用示例如下:
select student.sno,sname,avg(score)
from student
left join sc on student.sno=sc.sno
where student.sno like '2018%'
group by student.sno,sname
having avg(score)>60
order by avg(score)
(count、sum、avg、max、min)+(distinct/all 列名)
insert
into student (sno,sname,ssex,sdept,sage)
values('20182233','李小布','男','软件工程',21)
插入成功,运行结果如下图:
例2:在SC中插入一条选课记录,(‘20186666’,‘c1’)
insert into sc(sno,cno)
values('20186666','c1')
或者可以写成下面的样子,系统会把values里面的值对应到sc表中。
insert into sc
values('20186666','c1','NULL')
语法规则:insert into <表名> [<属性列>…]
子查询
例3:对每一个系,求学生的平均年龄,并把结果存入数据库。
题目要分为两步来做,首先建立新表,然后再插入数据。
第一步:建表
create table dept_age
(sdept char(15),
avg_age smallint
)
第二步:插入数据
insert into dept_age(sdept,avg_age)
select sdept,avg(sage)
from student
group by sdept
关系数据库管理系统会在执行插入语句时,检查所插元组是否破坏已定义的完整性规则。·
update Student
set sage=22
where sno='20172018'
例5:将所有学生年龄增加1岁
update Student
set sage=sage+1
例6:将软件工程系全体学生的成绩置为零
update sc
set score=0
where sno in(
select sno
from student
where sdept='软件工程')