数据库第四讲查询笔记

数据库笔记


第四讲 数据查询

--创建数据库
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);

1.SQL 是什么?

  • SQL,指的是结构化查询语言,全称是 Structured Query Language。
  • SQL 是一种 ANSI(American National Standards Institute 美国国家标准化组织)标准的计算机语言。

2.SQL能够干什么?

  • 查询数据
  • 在数据库中插入新的记录
  • 更新数据库中的数据
  • 从数据库删除记录
  • 创建新数据库
  • 在数据库中创建新表
  • 在数据库中创建存储过程
  • 在数据库中创建视图
  • 设置表、存储过程和视图的权限

单表查询

(一)选择表中的若干列(投影)

  1. 查询所有学生的学号和姓名。【例3.16】

    查询某字段的全体

    SELECT sno,sname FROM student
    
  2. 查询全体学生的详细记录。【例3.18】

    查询全体

    查询表中的一些字段信息

    SELECT * FROM student
    或:
    SELECT sno,sname,ssex,sage,sdept FROM student
    

    注意:

    建议根据**“用多少,投影多少”的原则明确指定查询字段名,而不推荐使用*作为查询字段列表。**

  3. 查询全体学生的姓名及出生年份。【例3.19】

    SELECT sname, 'birthYear'  ,		
    		  YEAR(GETDATE()) - sage
    	FROM student      
    	--或:
    SELECT sname,
    	       YEAR (GETDATE()) - sage AS birthYear --使用AS 重命名字段
    	FROM student
    

    在SQL Server中,通过 getdate() 函数获得当前的日期和时间。


(二)选择表中的若干元组(选择)

  1. 查询选修了课程的学生学号。【例3.21】

    DISTINCT用于取消重复的记录;

SELECT  DISTINCT  sno 	FROM sc;
--DISTINCT用于取消重复的记录;
--如果没有指定DISTINCT,则默认为ALL,即保留结果表中取值重复的记录。
  1. 查询计算机科学系全体学生的名单。【例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是“聚集索引扫描”。

  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)
    

    startdateenddate 参数是合法的日期表达式。

    datepart 参数可以是下列的值:

    yy, yyyy
    季度 qq, q
    mm, m
    年中的日 dy, y
    dd, d
    wk, ww
    星期 dw, w
    小时 hh
    分钟 mi, n
    ss, s
    毫秒 ms
    微妙 mcs
    纳秒 ns
  3. 查询计算机系、数学系和信息系的学生姓名和性别。【例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='数学系'
    
  4. 查询所有姓刘的学生的姓名、学号和性别。【例3.30】

    	SELECT sname,sno,ssex FROM student 
    	WHERE sname LIKE '刘%' 
    
  5. 查询姓为“欧阳”且全名为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等).
  6. 查询以“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'
    

    尽量减少不必要的查询,在已知的条件下

  7. 查询缺少成绩的学生的学号和课程号。【例3.36】

    SELECT sno,cno FROM sc 
    	WHERE grade IS NULL
    		-- 不能写成grade = NULL
    

    在查询NULL的时候要注意:

    • 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. 查询选修了1号课程的不及格的学生。

    SELECT sno FROM sc 
    WHERE cno = 'C001' AND grade < 60
    --Grade为NULL的记录不会被选择。
    

    Grade为NULL的记录不会被选择。

  2. 例题:

    设备表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可加可不加,因为默认是升序。


(三)ORDER BY子句

  1. 查询选修了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

  2. 查询全体学生情况,查询结果按所在系的系号升序排序,同一系中的学生按年龄降序排列。【例3.40】

    SELECT * 
    	FROM student
     	ORDER BY sdept,sage DESC --sdept是升序,sage是降序,用逗号隔开
    

(四)聚集函数

  1. 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值的记录数
    
  2. 查询选修了课程的学生人数。【例3.42】

    SELECT COUNT(DISTINCT sno) 
              FROM sc
    
    
  3. 计算1号(编号为“C001”)课程的学生平均成绩和最高分。【例3.43、3.44】

    	SELECT MAX(grade) AS 最高分,
    		    AVG(grade) AS 平均分 
    	FROM sc
    	WHERE cno = 'C001'
    

(五)GROUP BY子句

分组是使用数据库时必须处理的最重要任务之一。 要将行分组,请使用GROUP BY子句。

  1. 求各个课程号及相应的选课人数。【例3.46】

    SELECT cno,COUNT(*) 人数
    	FROM sc 
    	GROUP BY cno
    --cno课程号
    --SELECT子句中的列表只能包含在GROUP   BY指定的列或在聚集函数中指定的列。
    --通过课程号进行分组,求得每一个课程的人数
    -- count(*)可以加列名
    
  2. 某门课程成绩高于80分的学生的学号以及该生高于80分的课程平均成绩。

    	SELECT sno,AVG(grade)  FROM sc
    	WHERE grade > 80
    	GROUP BY sno
    	--sc表中 按照sno学号进行分组,查询分数高于80分的学号以及该生高于80分的课程平均成绩。
    
  3. 查询选修了3门及以上课程的学生学号。【例3.47】

    SELECT sno,COUNT(*) FROM sc
    	GROUP BY sno
    	HAVING COUNT(*) >= 3
    

    WHERE决定了哪些记录能够参加分组;
    HAVING决定了分组后哪些记录能够作为最终结果输出。


你可能感兴趣的:(数据库)