章节笔记:掌握 SQL(结构化查询语言)

各位同學好!欢迎来到数据库的世界。试想想你身边所有的资料:朋友的联络资料、学校的学生记录、网上购物网站上的商品等等。所有这些资讯是如何储存、管理和检索的?答案往往是一个数据库,而我们用来与它“沟通”的语言就是 SQL

在这些笔记中,我们将学习如何使用 SQL 来提出问题、更改资讯,甚至建立数据库的一部分。这就像学习一种秘密语言,它为你每天使用的许多应用程序和网站提供支持。刚开始时可能觉得有点难,但别担心,我们会通过大量例子一步步地将它拆解!


什么是 SQL?一个简单的比喻

想像一下你学校的图书馆有一个超级有条理的数字目录。SQL 就是你用来要求图书馆管理员(数据库管理系统,或称 DBMS)在该目录(数据库)中寻找、新增或更新书籍资讯的特殊语言。

  • 查询资料:“显示所有 J.K. Rowling 撰写的书籍。”
  • 新增资料:“将这本新书《资讯及通讯科技历险记》新增到系统中。”
  • 更新资料:“将《哈利波特》的状态从‘可借阅’更改为‘已借出’。”

SQL 有几种主要的指令类型。我们可以把它们想像成不同类型的请求:

  • 资料查询语言 (DQL):用于提出问题和获取资料。(最常用!)
  • 资料操作语言 (DML):用于更改资料(新增、更新、删除记录)。
  • 资料定义语言 (DDL):用于建立和管理数据库结构本身(建立或更改表格)。



第一部分:使用 SELECT 查询资料 (DQL)

这是 SQL 中最重要且最常用的部分,它全部关于检索资讯。其基本结构简单易记。

我们将使用一个名为 Students 的示例表格作为例子:

Students 表格

学生编号 | 名字 | 姓氏 | 班级 | 分数
101 | Chan | Tai Man | 5A | 88
102 | Lee | Siu Ming | 5B | 95
103 | Wong | Ka Wai | 5A | 72
104 | Ng | Mei Ling | 5C | 88
105 | Cheung | Pui Sze | 5B | 65

基本 SELECT 语句

两个必要的部分是 SELECT(你想要哪些字段)和 FROM(从哪个表格中查找)。

获取指定字段:

查找所有学生的名字和姓氏。

SELECT FirstName, LastName FROM Students;

获取所有字段(使用通配符 *):

查找所有学生的所有资讯。

SELECT * FROM Students;

记忆提示:* 想像成一个通配符,意思是“所有”。

使用 WHERE 过滤结果

如果你不想获取所有记录怎么办?WHERE 子句允许你设定条件来过滤结果。

查找 5A 班学生的名字。

SELECT FirstName, LastName FROM Students WHERE Class = '5A';

重要提示:文本值(如 '5A')通常放在单引号 ' ' 内。

WHERE 子句的运算符

你可以使用不同的运算符来建立强大的筛选条件:

  • 比较运算符:
    • = (等于)
    • <> (不等于)
    • > (大于)
    • < (小于)
    • >= (大于或等于)
    • <= (小于或等于)
  • 逻辑运算符:
    • AND:两个条件都必须为真。(例如:WHERE Class = '5A' AND Score > 80
    • OR:至少一个条件必须为真。(例如:WHERE Score < 70 OR Score > 90
    • NOT:反转条件的结果。(例如:WHERE NOT Class = '5A'
  • 特殊运算符:
    • BETWEEN:检查值是否在指定范围内(包含两端)。
      例子:WHERE Score BETWEEN 70 AND 90;(这等同于 Score >= 70 AND Score <= 90
    • IN:检查值是否与列表中任何值匹配。
      例子:WHERE Class IN ('5A', '5C');(这是 Class = '5A' OR Class = '5C' 的简写)
    • LIKE:用于文本的模式匹配。它使用通配符:
      • %:代表零个、一个或多个字符。
      • _:代表一个单一字符。
      例子 1:查找姓氏以 'W' 开头的学生。
      WHERE LastName LIKE 'W%';

      例子 2:查找名字是 'Siu' 后面跟着四个字符的学生。
      WHERE FirstName LIKE 'Siu ____';

使用 ORDER BY 排序结果

ORDER BY 子句会对你的结果进行排序。默认情况下,它按升序排序(A-Z,1-100)。

  • ASC:升序(默认值)。
  • DESC:降序。

列出所有学生,按分数从高到低排序。

SELECT FirstName, LastName, Score FROM Students ORDER BY Score DESC;

快速回顾:DQL 黄金三剑客

对于大多数查询,你会使用这个结构:

SELECT [字段]
FROM [表格]
WHERE [条件]
ORDER BY [排序字段];

你不一定总是需要 `WHERE` 或 `ORDER BY`,但它们必须按这个顺序出现!




第二部分:汇总及操作资料(选修内容)

现在我们将进入数据库选修部分涵盖的更进阶主题。这正是 SQL 变得真正强大的地方!

聚合函数:全盘概览

这些函数对一组行执行计算,并返回一个单一的汇总值。

  • COUNT():计算行数。
  • SUM():计算字段中所有值的总和。
  • AVG():计算字段中值的平均值。
  • MAX():查找字段中的最高值。
  • MIN():查找字段中的最低值。

总共有多少学生?

SELECT COUNT(*) FROM Students;

5A 班学生的平均分数是多少?

SELECT AVG(Score) FROM Students WHERE Class = '5A';

字符串函数:处理文本

SQL 有用于处理文本资料的函数。确切的名称可能有所不同,但概念是相似的。

  • LENGTH()LEN():获取字符串的字符数。
  • UCASE()UPPER():将文本转换为大写。
  • LCASE()LOWER():将文本转换为小写。

显示所有学生姓氏的大写形式。

SELECT UCASE(LastName) FROM Students;

使用 DML 更改资料

这些指令修改表格内部的资料。

注意! DML 的一个错误可能会永久性地更改或删除你的资料。使用 WHERE 子句时务必小心!

INSERT INTO:新增资料

向表格新增一行(记录)。

向表格新增一个学生。

INSERT INTO Students (StudentID, FirstName, LastName, Class, Score) VALUES (106, 'Lau', 'Kit Ying', '5C', 81);

UPDATE:修改现有资料

更改现有行中的资料。

常见错误:忘记 `WHERE` 子句将更新表格中的所有行!

Chan Tai Man(学生编号 101)重考了一次,现在他的分数是 91。

UPDATE Students SET Score = 91 WHERE StudentID = 101;

DELETE:删除资料

从表格中删除行。

常见错误:忘记 `WHERE` 子句将删除表格中的所有行!

学生 Cheung Pui Sze(学生编号 105)已离校。

DELETE FROM Students WHERE StudentID = 105;

重点:DML 的安全使用

WHERE 子句是 UPDATEDELETE 的安全网。它告诉数据库确切要更改或删除哪条记录。在执行指令前务必仔细检查!




第三部分:使用连接及子查询进行进阶查询(选修内容)

真实世界的数据库为了提高效率,会将资料分散储存于多个表格中。我们如何将它们组合起来呢?使用连接 (JOINs)

让我们新增另一个表格:Courses

Courses 表格

课程编号 | 课程名称 | 教师
ICT | 资讯科技 | 李先生
ENG | 英文 | 戴维斯女士
MATH| 数学 | 陈太太

前提知识:主键与外键

为了连接表格,我们需要特殊的键。

  • 主键 (PK) 是表格中唯一识别每条记录的字段(例如 Students 表格中的 `StudentID`)。
  • 外键 (FK) 是来自一个表格的主键,你将其放入另一个表格中以建立连接。

连接表格

连接 (JOIN) 根据表格之间相关的字段将两个或多个表格中的行组合起来。

等值连接(或称内部连接 INNER JOIN)

这是最常见的连接类型。它只返回在两个表格中都有匹配值的记录。

让我们想像我们有第三个表格 Enrollments,它连接 Students 和 Courses。

Enrollments 表格

学生编号 | 课程编号
101 | ICT
101 | ENG
102 | ICT
103 | MATH

显示每个学生的名字以及他们报读的课程名称。

SELECT S.FirstName, C.CourseName
FROM Students S JOIN Enrollments E ON S.StudentID = E.StudentID
JOIN Courses C ON E.CourseID = C.CourseID;

解释:
1. 我们使用别名(S 代表 StudentsC 代表 Courses)来缩短程序代码。
2. ON 关键字指定连接条件:`ON table1.column = table2.column`。

外部连接(左连接 LEFT JOIN 和右连接 RIGHT JOIN)

如果你想查看一个表格中的所有记录,即使它们在另一个表格中没有匹配项,该怎么办?

  • LEFT JOIN(左连接):返回左侧表格(首先提到的表格)中的所有记录,以及右侧表格中匹配的记录。如果没有匹配项,右侧结果为空值 (NULL)。
  • RIGHT JOIN(右连接):返回右侧表格中的所有记录。它与左连接相反。

列出所有学生及其所修读的课程。即使没有修读任何课程的学生也应列出。

SELECT S.FirstName, E.CourseID
FROM Students S LEFT JOIN Enrollments E ON S.StudentID = E.StudentID;

这将显示 Chan Tai Man 和 Lee Siu Ming 及其课程,但 Wong Ka Wai、Ng Mei Ling 等也会被列出,其 `CourseID` 为空值 (NULL),因为它们在左侧表格(Students)中,但在 Enrollments 表格中没有匹配项。

自然连接 (Natural Join)

NATURAL JOIN(自然连接)是一种等值连接,数据库会根据具有相同名称的字段自动连接表格。它很方便,但如果表格有多个同名字段,可能会产生不可预知的结果。

(在我们的例子中,为了使用它,我们需要将两个表格中的字段都重命名为 `StudentID`)。

SELECT FirstName, CourseID FROM Students NATURAL JOIN Enrollments;

子查询(单层)

子查询是嵌套在另一个查询中的查询。内部查询的结果被外部查询使用。

查找分数高于班级平均分的学生姓名。

SELECT FirstName, LastName
FROM Students
WHERE Score > (SELECT AVG(Score) FROM Students);

逐步解释:
1. 内部查询 (SELECT AVG(Score) FROM Students) 首先执行,并计算平均分数(例如 82)。
2. 然后外部查询执行为:SELECT FirstName, LastName FROM Students WHERE Score > 82;

重点:组合资料

连接 (JOINs) 用于组合来自不同表格的字段。子查询 用于将一个查询的结果作为另一个查询的条件。




第四部分:视图和表格结构(选修内容)

建立视图 (VIEW)

视图 (VIEW) 是基于 SQL 语句结果集的一个虚拟表格。它就像一个已储存的查询,你可以像操作真实表格一样与它互动。视图对于以下方面很有用:

  • 简化复杂的查询。
  • 通过只显示某些字段或行来提供一层安全性。

建立一个只显示 5A 班学生的视图。

CREATE VIEW Class5A_Students AS
SELECT StudentID, FirstName, LastName, Score
FROM Students
WHERE Class = '5A';

现在,你可以直接查询这个视图:

SELECT * FROM Class5A_Students;

使用 DDL 修改表格结构

有时候你需要更改表格建立后的结构(即“模式”)。我们使用 ALTER TABLE 来实现这一点。

  • ADD Column:向表格新增一个字段。
  • DROP COLUMN:移除一个字段。
  • MODIFY COLUMNALTER COLUMN:更改字段的资料类型。

向 Students 表格新增一个名为 'Email' 的新字段。

ALTER TABLE Students ADD Email VARCHAR(255);

(VARCHAR 是一种常用的可变长度文本资料类型)。

移除我们刚刚新增的 'Email' 字段。

ALTER TABLE Students DROP COLUMN Email;

你知道吗?

SQL 最初于 1970 年代初由 IBM 开发。它最初的名字是 SEQUEL(结构化英文查询语言)。尽管它已有将近 50 年的历史,但它仍然是全球科技职位中最受欢迎的技能之一!


最后总结

你已经学会了 SQL 的基础知识!从简单的 SELECT...FROM...WHERE 查询到复杂的资料操作和多表格连接 (JOINs)。实践是关键,所以试着为不同的情景编写你自己的查询吧。做得好!