--创建数据库
CREATE DATABASE StudentSys;
GO
--创建表
USE StudentSys;
CREATE TABLE student
(
sno CHAR(6) PRIMARY KEY,
sname VARCHAR(8) not null,
ssex CHAR(2) not null,
sage TINYINT not null,
sdept VARCHAR(20)
);
CREATE TABLE course
(
cno CHAR(4) PRIMARY KEY,
cname VARCHAR(30) UNIQUE not null,
cpno CHAR(4),
ccredit TINYINT not null,
FOREIGN KEY (cpno) REFERENCES course(cno)
);
CREATE TABLE sc
(
sno CHAR(6),
cno CHAR(4),
grade TINYINT,
PRIMARY KEY(sno,cno),
FOREIGN KEY (sno) REFERENCES student(sno),
FOREIGN KEY (cno) REFERENCES course(cno)
);
--往student表中插入记录
INSERT INTO student(sno,sname,ssex,sage,sdept)
VALUES('990001','李勇','男',20,'计算机系');
INSERT INTO student(sno,sname,ssex,sage,sdept)
VALUES('990002','刘晨','女',19,'计算机系');
INSERT INTO student(sno,sname,ssex,sage,sdept)
VALUES('990003','王敏','女',18,'数学系');
INSERT INTO student(sno,sname,ssex,sage,sdept)
VALUES('990004','欧阳珊','女',19,'数学系');
INSERT INTO student(sno,sname,ssex,sage,sdept)
VALUES('990005','张立','男',19,'信息系');
INSERT INTO student(sno,sname,ssex,sage,sdept)
VALUES('990006','欧阳小峰','男',20,'信息系');
--往course表中插入记录
INSERT INTO course(cno,cname,cpno,ccredit)
VALUES('C001','数据库',NULL,4);
INSERT INTO course(cno,cname,cpno,ccredit)
VALUES('C002','数学',NULL,2);
INSERT INTO course(cno,cname,cpno,ccredit)
VALUES('C003','信息系统',NULL,4);
INSERT INTO course(cno,cname,cpno,ccredit)
VALUES('C004','操作系统',NULL,3);
INSERT INTO course(cno,cname,cpno,ccredit)
VALUES('C005','数据结构',NULL,4);
INSERT INTO course(cno,cname,cpno,ccredit)
VALUES('C006','数据处理',NULL,2);
INSERT INTO course(cno,cname,cpno,ccredit)
VALUES('C007','DB_Design',NULL,4);
UPDATE course SET cpno='C005' WHERE cno='C001';
UPDATE course SET cpno='C001' WHERE cno='C003';
UPDATE course SET cpno='C006' WHERE cno='C004';
UPDATE course SET cpno='C007' WHERE cno='C005';
UPDATE course SET cpno='C006' WHERE cno='C007';
--往sc表中插入记录
INSERT INTO SC(sno,cno,grade)
VALUES('990001','C001',92);
INSERT INTO SC(sno,cno,grade)
VALUES('990001','C002',93);
INSERT INTO SC(sno,cno,grade)
VALUES('990002','C001',80);
INSERT INTO SC(sno,cno,grade)
VALUES('990002','C002',82);
INSERT INTO SC(sno,cno,grade)
VALUES('990003','C001',70);
INSERT INTO SC(sno,cno,grade)
VALUES('990003','C002',90);
INSERT INTO SC(sno,cno,grade)
VALUES('990003','C003',90);
INSERT INTO SC(sno,cno,grade)
VALUES('990003','C004',82);
INSERT INTO SC(sno,cno,grade)
VALUES('990003','C005',75);
INSERT INTO SC(sno,cno,grade)
VALUES('990003','C006',90);
INSERT INTO SC(sno,cno,grade)
VALUES('990003','C007',88);
查询所有学生的学号和姓名。【例3.16】
查询某字段的全体
SELECT sno,sname FROM student
查询全体学生的详细记录。【例3.18】
查询全体
查询表中的一些字段信息
SELECT * FROM student
或:
SELECT sno,sname,ssex,sage,sdept FROM student
注意:
建议根据**“用多少,投影多少”的原则明确指定查询字段名,而不推荐使用*作为查询字段列表。**
查询全体学生的姓名及出生年份。【例3.19】
SELECT sname, 'birthYear' ,
YEAR(GETDATE()) - sage
FROM student
--或:
SELECT sname,
YEAR (GETDATE()) - sage AS birthYear --使用AS 重命名字段
FROM student
在SQL Server中,通过 getdate() 函数获得当前的日期和时间。
查询选修了课程的学生学号。【例3.21】
DISTINCT用于取消重复的记录;
SELECT DISTINCT sno FROM sc;
--DISTINCT用于取消重复的记录;
--如果没有指定DISTINCT,则默认为ALL,即保留结果表中取值重复的记录。
查询计算机科学系全体学生的名单。【例3.22】
查询全体—某字段为***的元组
SELECT * FROM student
WHERE sdept = '计算机系'
--如果student表中记录很少,就算在sdept字段上建立了索引,查询分析器未必会选择该索引。
--若索引idx_sdept创建代码如下:
CREATE INDEX idx_sdept ON student(sdept)
--则强制使用该索引进行查询的语句为:
SELECT * FROM student WITH(index= idx_sdept)
WHERE sdept = '计算机系'
注意:
在SQL Server中,也可能因为数据类型的不同而导致“索引查找”失效。
在表设计器中,修改orders_test的OrderID字段的数据类型为char(5),并设置OrderID为主键。
SELECT * FROM orders WHERE OrderID='10248'
-- orders表的主键OrderID为int型
SELECT * FROM orders_test WHERE OrderID=10248
-- orders_test表的主键OrderID为char(5)
查询1与查询2的查询结果相同,但查询1的执行计划是“聚集索引查找”,查询2是“聚集索引扫描”。
查询年龄在20-23之间的学生姓名、系和年龄。【例3.25】
查询在某字段范围内的元组–有限定范围的----某字段在一定的范围内的元组(大小-区间)
SELECT sname,sdept,sage
FROM student
WHERE sage BETWEEN 20 AND 23--(从小到大)
-- 不能写成 sage BETWEEN 23 AND 20
--或:
SELECT sname,sdept,sage
FROM student
WHERE sage>=20 AND sage<=23
【练习】设订单表orders的相关代码如下,请查询“2001/1/11与2001/1/12下单的全部订单记录”。
create table orders--创建表
(order_id int primary key identity(1,1),
order_time datetime);
insert into orders(order_time)
values('2001/01/11 0:0:01')
,('2001/01/11 12:30:30')
,('2001/01/12 12:30:30');
--答:
select * from orders
where datediff(day,order_time,'2001/01/11')
between -1 and 0
--不能写成:where order_time
between '2001/01/11' and '2001/01/12'
函数学习:
datadiff:
定义:DATEDIFF() 函数返回两个日期之间的时间。
语法:
DATEDIFF(datepart,startdate,enddate)
startdate 和 enddate 参数是合法的日期表达式。
datepart 参数可以是下列的值:
年 | yy, yyyy |
---|---|
季度 | qq, q |
月 | mm, m |
年中的日 | dy, y |
日 | dd, d |
周 | wk, ww |
星期 | dw, w |
小时 | hh |
分钟 | mi, n |
秒 | ss, s |
毫秒 | ms |
微妙 | mcs |
纳秒 | ns |
查询计算机系、数学系和信息系的学生姓名和性别。【例3.28】
查询符合多个条件 或 的元组,满足其中的一个条件
用 IN操作符
IN 操作符允许我们在 WHERE 子句中规定多个值。
SELECT column_name(s)
FROM table_name
WHERE column_name IN (value1,value2,..=.)
SELECT sname,ssex FROM student
WHERE sdept IN ('计算机系','信息系','数学系')
或:
SELECT sname,ssex FROM student
WHERE sdept = '计算机系'
or sdept='信息系' or sdept='数学系'
查询所有姓刘的学生的姓名、学号和性别。【例3.30】
SELECT sname,sno,ssex FROM student
WHERE sname LIKE '刘%'
查询姓为“欧阳”且全名为3个汉字的学生姓名。【例3.31】
使用LIKE实现模糊查询
SELECT sname FROM student
WHERE sname LIKE '欧阳_'
通配符 | 说明 | 示例 |
---|---|---|
% | 包含零个或多个字符的任意字符串 | WHERE title like ‘%computer%’ 将查找在书名中任意位置包含单词"computer"的所有书名。 |
_(下划线) | 任何单个字符 | WHERE au_fname **like '_**ean’将查找以ean 结尾的所有 4 个字母的名字(Dean、Sean等). |
查询以“DB_”开头,且倒数第3个字符为i的课程的详细情况。【例3.35】
SELECT * FROM course
WHERE cname LIKE ‘DB_%i__’ ESCAPE’’
(1)默认情况下,字符串的查询为大小写无关(大写和小写字母视为相同字符)。
(2)要进行大小写相关的查询,则需要在查询条件后面加上:collate Chinese_PRC_CS_AS_WS,即:
SELECT cname FROM course
WHERE cname LIKE ‘DB_%i__’ ESCAPE’’
collate Chinese_PRC_CS_AS_WS
举例:
SELECT * FROM orders WHERE customerID like 'CENT_'
--返回1行,CustomerID索引查找
SELECT * FROM orders WHERE customerID like '%CENTC'
--左模糊查询,返回1行,CustomerID索引查找
SELECT * FROM orders WHERE customerID like '%ENT%'
--全模糊查询,返回1行,CustomerID索引查找
使用like需要注的是:使用like,系统可能无法正确使用索引
SELECT * FROM orders WHERE customerID like 'VINE_'
--返回5行,聚集索引扫描,逻辑读取22次
例题:
在northwind数据库的orders表中,根据客户编号customersID进行查询。已知客户编号由五个大写字母组成,前四个字母为“VINE”,最后一个字母不确定。请写出符合上述需求的SQL语句。
--1、使用like:聚集索引扫描,逻辑读取22次
SELECT * FROM orders WHERE customerID like 'VINE_'
--2、使用>=和<=:customerID索引查询,逻辑读取12次
SELECT * FROM orders WHERE customerID >= 'VINEA'
and customerID<='VINEZ'
尽量减少不必要的查询,在已知的条件下
查询缺少成绩的学生的学号和课程号。【例3.36】
SELECT sno,cno FROM sc
WHERE grade IS NULL
-- 不能写成grade = NULL
在查询NULL的时候要注意:
关于NULL值的用法,有以下要点:
1、查询没有先修课程的所有课程的基本信息。
SELECT * FROM course
WHERE cpno IS NULL--选择为NULL值的记录
如果查询的是“有先修课程”的所有课程的基本信息,则使用的条件为:
WHERE cpno IS NOT NULL --选择不为NULL值的记录
2、NULL值与任何值(包括NULL值)进行比较(包括:=、>、!=等)的结果均为UNKNOWN。在查询语句中,只有使得WHERE子句中选择条件为TRUE的记录才能被选择出来。
3、在SQL Server中,将NULL值看成最小值,因此若按照升序排,含NULL值的元组最先显示;按降序排,NULL值的元组最后显示。
查询选修了1号课程的不及格的学生。
SELECT sno FROM sc
WHERE cno = 'C001' AND grade < 60
--Grade为NULL的记录不会被选择。
Grade为NULL的记录不会被选择。
例题:
设备表device的SQL脚本如下。
CREATE TABLE device
(device_code INT PRIMARY KEY,–设备编号
device_name VARCHAR(50),–设备名称
buy_time DATE–购买日期
);
INSERT INTO device
VALUES(101,‘鼠标’,‘2020-1-1’),(102,‘键盘’,NULL),
(103,‘投影仪’,‘2020-1-2’),(104,‘手写板’,‘2020-1-3’),
(105,‘扫描仪’,NULL)
请写出满足要求的SQL语句。
1、找出不在2020年1月1日购买的所有设备的全部信息。
(可以用 != 或者 <> 表示“不等于”)
2、请找出最早购买的设备的设备编号和设备名称。
(正确的输出应为: 101 2020-1-1)
SELECT TOP 1 device_code ,buy_time
FROM device
where buy_time is not null
ORDER BY buy_time asc;
ORDER BY 中asc可加可不加,因为默认是升序。
查询选修了3号课程的学生的学号和成绩,查询结果按分数的降序排列。【例3.39】
SELECT sno,grade FROM sc
WHERE cno='C003'
ORDER BY grade desc:
SELECT TOP 3 sno,grade FROM sc
WHERE cno= 'C003' ORDER BY grade desc
---TOP语句用于限制输出的记录行数。
降序是 desc,升序是asc
查询全体学生情况,查询结果按所在系的系号升序排序,同一系中的学生按年龄降序排列。【例3.40】
SELECT *
FROM student
ORDER BY sdept,sage DESC --sdept是升序,sage是降序,用逗号隔开
count
查询学生总人数。【例3.41】
SELECT COUNT(*) FROM student
或: SELECT COUNT(sno) FROM student
-- *与sno是不一样的
-- 在course表中cpno存在NULL值的情况下,以下两条语句结果不同:
select count(*) from course
--返回course表的总记录数
select count(cpno) from course
--返回course表中cpno不为NULL值的记录数
查询选修了课程的学生人数。【例3.42】
SELECT COUNT(DISTINCT sno)
FROM sc
计算1号(编号为“C001”)课程的学生平均成绩和最高分。【例3.43、3.44】
SELECT MAX(grade) AS 最高分,
AVG(grade) AS 平均分
FROM sc
WHERE cno = 'C001'
分组是使用数据库时必须处理的最重要任务之一。 要将行分组,请使用GROUP BY
子句。
求各个课程号及相应的选课人数。【例3.46】
SELECT cno,COUNT(*) 人数
FROM sc
GROUP BY cno
--cno课程号
--SELECT子句中的列表只能包含在GROUP BY指定的列或在聚集函数中指定的列。
--通过课程号进行分组,求得每一个课程的人数
-- count(*)可以加列名
某门课程成绩高于80分的学生的学号以及该生高于80分的课程平均成绩。
SELECT sno,AVG(grade) FROM sc
WHERE grade > 80
GROUP BY sno
--sc表中 按照sno学号进行分组,查询分数高于80分的学号以及该生高于80分的课程平均成绩。
查询选修了3门及以上课程的学生学号。【例3.47】
SELECT sno,COUNT(*) FROM sc
GROUP BY sno
HAVING COUNT(*) >= 3
WHERE决定了哪些记录能够参加分组;
HAVING决定了分组后哪些记录能够作为最终结果输出。