零基础学习 SQL:常用语句指南 – wiki基地


零基础学习 SQL:常用语句指南

欢迎来到数据世界的大门!如果你曾对那些复杂的数据报表、用户列表、产品库存感到好奇,想知道它们是如何被管理和提取的,那么学习 SQL(Structured Query Language,结构化查询语言)将是你的第一步。SQL 是一种用于管理关系型数据库的标准语言,它是数据分析、软件开发、数据科学等众多领域不可或缺的技能。

许多人认为编程很难,但 SQL 相对来说更容易上手。它更像是一种指令语言,你用清晰的指令告诉数据库“给我这个数据”、“修改那个数据”或“创建这样一个数据结构”。

本篇文章将从零开始,带你逐步了解 SQL 的核心概念和最常用的语句。我们将从最简单的数据查询开始,然后学习如何插入、更新和删除数据,最后触及如何定义和修改数据结构,以及如何进行更复杂的数据筛选和分组。读完这篇文章,你将能够理解和编写基本的 SQL 查询,为进一步深入学习打下坚实的基础。

文章目录

  1. SQL 是什么?为什么学它?
    • SQL 的定义和作用
    • SQL 的应用领域
    • 学习 SQL 的优势
  2. 数据库基础概念入门
    • 数据库 (Database)
    • 表 (Table)
    • 列 (Column / Field)
    • 行 (Row / Record)
    • 关系型数据库的核心思想
  3. 准备实践环境
    • 选择一个数据库系统 (SQLite, MySQL, PostgreSQL, SQL Server)
    • 推荐及获取方式 (以 SQLite 为例)
    • 创建一个示例数据库和表
  4. SQL 核心语句 (CRUD)
    • SELECT:查询数据 (Read)
      • SELECT *: 查询所有列
      • SELECT column1, column2: 查询指定列
      • FROM table_name: 指定从哪个表查询
      • 实践演练与示例
    • INSERT INTO:插入数据 (Create)
      • 插入所有列的值
      • 插入指定列的值
      • 实践演练与示例
    • UPDATE:更新数据 (Update)
      • SET column = value: 指定要更新的列和值
      • WHERE condition: 指定更新哪一行(非常重要!
      • 实践演练与示例 (含不使用 WHERE 的警告)
    • DELETE FROM:删除数据 (Delete)
      • WHERE condition: 指定删除哪一行(非常重要!
      • 实践演练与示例 (含不使用 WHERE 的警告)
  5. 数据定义语句 (DDL)
    • CREATE TABLE:创建表
      • 指定表名、列名和数据类型
      • 常用数据类型介绍 (INT, VARCHAR, TEXT, DATE, FLOAT, BOOLEAN)
      • 定义主键 (PRIMARY KEY)
      • 实践演练与示例
    • ALTER TABLE:修改表结构
      • 添加列 (ADD COLUMN)
      • 删除列 (DROP COLUMN)
      • 实践演练与示例
    • DROP TABLE:删除表
      • 实践演练与示例 (含警告)
  6. 进阶查询技巧
    • WHERE 子句详解:条件筛选
      • 比较运算符 (=, !=, >, <, >=, <=)
      • 逻辑运算符 (AND, OR, NOT)
      • 范围查询 (BETWEEN)
      • 集合查询 (IN)
      • 模糊匹配 (LIKE 和通配符 %, _)
      • 空值判断 (IS NULL, IS NOT NULL)
      • 实践演练与示例
    • ORDER BY 子句:排序结果
      • 升序 (ASC) 与降序 (DESC)
      • 按多个列排序
      • 实践演练与示例
    • LIMIT / TOP 子句:限制结果数量
      • 不同数据库系统的语法差异
      • 实践演练与示例
    • DISTINCT 关键字:去除重复行
      • 实践演练与示例
  7. 聚合函数与分组
    • 常用聚合函数: COUNT(), SUM(), AVG(), MIN(), MAX()
    • GROUP BY 子句:按列分组
      • 如何在分组中使用聚合函数
      • 实践演练与示例
    • HAVING 子句:筛选分组
      • WHEREHAVING 的区别
      • 实践演练与示例
  8. 连接多个表 (JOIN 入门)
    • 为什么需要连接表?关系型数据库的优势
    • INNER JOIN:内连接
      • 连接条件 (ON)
      • 实践演练与示例 (简单示例)
  9. 总结与下一步学习
    • 回顾常用语句
    • 鼓励实践
    • 推荐进一步学习方向 (外连接, 子查询, 索引, 事务等)

1. SQL 是什么?为什么学它?

SQL 的定义和作用

SQL,全称 Structured Query Language,即结构化查询语言。它是一种专门用来与数据库沟通的语言。想象一下数据库是巨大的电子档案馆,里面存放着按照特定规则组织好的信息(数据)。SQL 就是你用来对这个档案馆发号施令的语言:

  • “找出所有年龄大于 25 岁的用户。”
  • “给我上周所有的新订单。”
  • “把某个产品的库存数量减少 10。”
  • “创建一个新的空间来存放客户的地址信息。”

SQL 不是一种通用的编程语言(比如 Python、Java),它主要专注于数据的管理和操作。尽管存在不同的数据库系统(如 MySQL, PostgreSQL, SQL Server, Oracle, SQLite 等),它们都使用 SQL,只是在一些高级功能或特定语法上略有差异,但核心的常用语句是通用的。

SQL 的应用领域

SQL 几乎渗透在所有与数据相关的领域:

  • 软件开发: 绝大多数网站、应用程序的后端都需要与数据库交互来存储和读取用户数据、产品信息、日志等。
  • 数据分析: 分析师使用 SQL 从海量数据中提取有价值的信息,生成报表、洞察用户行为、进行业务决策。
  • 数据科学/机器学习: 数据科学家通常需要先使用 SQL 清理、转换和准备数据,然后才能用于建模。
  • 数据库管理: 数据库管理员 (DBA) 使用 SQL 来维护、优化数据库的性能和安全。
  • 商业智能 (BI): 构建仪表板和报告的工具通常底层都依赖 SQL 来获取数据。

学习 SQL 的优势

  • 高需求: SQL 是数据相关职位的基本要求,掌握它能显著提升你的就业竞争力。
  • 通用性强: 一旦掌握了标准 SQL,你可以相对轻松地适应不同的数据库系统。
  • 理解数据: 学习 SQL 能让你更好地理解数据的组织方式和如何有效地获取所需信息。
  • 门槛相对低: 相比其他编程语言,SQL 的概念和语法更接近自然语言,更容易入门。

2. 数据库基础概念入门

在我们开始学习 SQL 语句之前,理解一些数据库的基本术语至关重要。

  • 数据库 (Database): 可以想象它是一个大型的电子档案馆,是存储数据的整体容器。一个数据库可以包含一个或多个表。
  • 表 (Table): 数据库中最基本的数据存储单元。它类似于电子表格(如 Excel)中的一个工作表。每个表都用来存储特定类型的数据,比如一个表存储“用户信息”,另一个表存储“产品信息”。表由行和列组成。
  • 列 (Column / Field): 表中的一个垂直方向的类别。每列存储特定类型的数据(例如,用户的姓名、产品的价格)。列有名字(列名)和数据类型(例如,文本、数字、日期)。
  • 行 (Row / Record): 表中的一个水平方向的记录。每一行代表一个独立的数据实体(例如,一个特定的用户、一个特定的产品)。一行包含了该实体在每一列上的具体值。
  • 关系型数据库的核心思想: 关系型数据库将数据存储在相互关联的表中。表之间的关系通常通过共享某些列(称为键,特别是主键和外键)来建立。这种结构化的存储方式使得数据的查询、管理和维护变得高效和灵活。我们将在后续的 JOIN 部分初步体会这种“关系”的好处。

举例:

想象一个存储学生信息的数据库:

  • 数据库: 学校管理系统数据库
  • 表: Students (学生表)
  • 列: StudentID (学生ID), FirstName (名), LastName (姓), Age (年龄), Major (专业)
  • 行:
    • 一行代表张三:StudentID=101, FirstName=’三’, LastName=’张’, Age=20, Major=’计算机科学’
    • 另一行代表李四:StudentID=102, FirstName=’四’, LastName=’李’, Age=21, Major=’物理’

学习 SQL 的过程,本质上就是学习如何用 SQL 语句来操作这些表中的行和列。

3. 准备实践环境

学习任何编程或查询语言,动手实践是最好的方法。幸运的是,入门 SQL 非常容易设置环境。你不需要安装大型的数据库服务器,可以选择一个轻量级的工具。

推荐及获取方式 (以 SQLite 为例)

对于初学者,强烈推荐使用 SQLite

  • 优点:
    • 非常轻量级,整个数据库就是一个.sqlite文件。
    • 无需安装服务器,易于设置。
    • 语法符合标准 SQL,学到的知识可以迁移到其他数据库。
    • 有很多图形界面工具 (GUI) 可以方便地管理和查询。
  • 获取方式:
    • SQLite 命令行工具: 访问 https://www.sqlite.org/download.html 下载预编译的二进制文件,它是一个单独的可执行文件,直接运行即可进入命令行界面。
    • SQLite GUI 工具: 有许多免费或付费的图形界面工具,让你可以通过点击、拖拽来管理数据库,并且有更友好的查询编辑器。推荐的有:DB Browser for SQLite (免费开源, https://sqlitebrowser.org/)、DBeaver (通用数据库工具, 支持 SQLite 及其他多种数据库, https://dbeaver.io/)。安装其中一个 GUI 工具将极大地方便你的学习。

创建一个示例数据库和表

无论你选择命令行还是 GUI 工具,第一步通常是创建一个新的数据库文件。然后,我们需要创建一个或多个表来存放数据。让我们创建一个简单的 Students 表,用于后续的练习。

使用 GUI 工具通常可以通过菜单或按钮来创建数据库文件和表。如果在 SQLite 命令行中,你可以:

  1. 打开命令行工具,输入 sqlite3 mydatabase.sqlite (或者你喜欢的任何文件名)。如果文件不存在,SQLite 会为你创建一个新的数据库文件;如果存在,它会打开该数据库。
  2. 输入以下 SQL 语句来创建 Students 表:

sql
CREATE TABLE Students (
StudentID INTEGER PRIMARY KEY,
FirstName VARCHAR(50) NOT NULL,
LastName VARCHAR(50) NOT NULL,
Age INT,
Major VARCHAR(100),
EnrollmentDate DATE
);

解释这段 CREATE TABLE 语句:

  • CREATE TABLE Students: 告诉数据库我们要创建一个名为 Students 的新表。
  • 圆括号 () 里面定义了表的列。
  • 每一行定义一列:列名 数据类型 [约束], 例如:
    • StudentID INTEGER PRIMARY KEY: 创建一个名为 StudentID 的列,数据类型是 INTEGER (整数)。PRIMARY KEY 是一个约束,表示这列的值必须唯一,且不能为空,它通常用来唯一标识表中的每一行。
    • FirstName VARCHAR(50) NOT NULL: 创建 FirstName 列,数据类型是 VARCHAR(50) (变长字符串,最多 50 个字符)。NOT NULL 约束表示这列的值不能为空。
    • LastName VARCHAR(50) NOT NULL: 类似 FirstName
    • Age INT: 创建 Age 列,数据类型是 INT (整数)。
    • Major VARCHAR(100): 创建 Major 列,数据类型是 VARCHAR(100),允许为空。
    • EnrollmentDate DATE: 创建 EnrollmentDate 列,数据类型是 DATE (日期)。
  • 每列的定义之间用逗号 , 分隔。
  • 语句末尾用分号 ; 结束(这是一个好习惯,虽然有些工具允许省略)。

执行这个语句后,你就拥有了一个空的 Students 表,可以开始学习如何操作它了。

4. SQL 核心语句 (CRUD)

CRUD 是数据库操作中最常用的四个基本功能的首字母缩写:

  • Create (创建 – 对应 SQL 的 INSERT)
  • Read (读取 – 对应 SQL 的 SELECT)
  • Update (更新 – 对应 SQL 的 UPDATE)
  • Delete (删除 – 对应 SQL 的 DELETE)

我们先从最常用的 SELECT 开始。

4.1 SELECT:查询数据 (Read)

SELECT 语句用于从数据库表中检索数据。它是 SQL 中最常用的语句,也是你学习的重点。

基本语法:

sql
SELECT column1, column2, ...
FROM table_name
[WHERE condition]; -- 方括号表示可选部分

或者查询所有列:

sql
SELECT *
FROM table_name
[WHERE condition];

  • SELECT: 关键字,表示要查询数据。
  • column1, column2, ...: 你想要查询的列的名称,用逗号分隔。
  • *: 星号代表查询表中的所有列。
  • FROM table_name: 指定你要从哪个表中查询数据。
  • WHERE condition: (可选) 指定筛选条件,只有满足条件的行才会被返回。我们会在后面详细讲解 WHERE 子句。

实践演练与示例:

首先,我们需要向表中添加一些数据,才能看到查询结果。我们可以先手动添加几行数据(使用 INSERT 语句,虽然还没正式学到,但先用起来):

sql
-- 假设已经创建了 Students 表
INSERT INTO Students (StudentID, FirstName, LastName, Age, Major, EnrollmentDate) VALUES (101, '三', '张', 20, '计算机科学', '2022-09-01');
INSERT INTO Students (StudentID, FirstName, LastName, Age, Major, EnrollmentDate) VALUES (102, '四', '李', 21, '物理', '2021-09-01');
INSERT INTO Students (StudentID, FirstName, LastName, Age, Major, EnrollmentDate) VALUES (103, '五', '王', 20, '计算机科学', '2022-09-01');
INSERT INTO Students (StudentID, FirstName, LastName, Age, Major, EnrollmentDate) VALUES (104, '六', '赵', 22, '数学', '2020-09-01');
INSERT INTO Students (StudentID, FirstName, LastName, Age, Major, EnrollmentDate) VALUES (105, '七', '钱', 21, '计算机科学', '2021-09-01');

现在,我们可以开始查询了。

示例 1:查询 Students 表中的所有数据

sql
SELECT *
FROM Students;

  • 解释: 这条语句会返回 Students 表中的所有列和所有行。

示例 2:查询 Students 表中学生的姓名和年龄

sql
SELECT FirstName, LastName, Age
FROM Students;

  • 解释: 这条语句只会返回 Students 表中 FirstName, LastName, 和 Age 这三列的数据。

示例 3:查询 Students 表中所有学生的专业

sql
SELECT Major
FROM Students;

  • 解释: 这会列出所有学生的专业。注意,如果多个学生专业相同,结果中会出现重复的专业名称。如果想去除重复项,可以使用 DISTINCT 关键字(稍后会讲)。

4.2 INSERT INTO:插入数据 (Create)

INSERT INTO 语句用于向表中添加新的行(记录)。

基本语法 1 (为所有列提供值):

sql
INSERT INTO table_name VALUES (value1, value2, value3, ...);

  • 这种方式要求你按照表中列的定义顺序,为 所有 列提供一个值。如果表的列很多或者顺序不确定,这种方式容易出错。

基本语法 2 (为指定列提供值):

sql
INSERT INTO table_name (column1, column2, column3, ...)
VALUES (value1, value2, value3, ...);

  • 这种方式更常用和推荐。你明确指定要插入值的列,然后按顺序提供对应的值。未指定的列如果允许为空 (NULL) 且没有默认值,将会被设置为 NULL

实践演练与示例:

继续使用我们的 Students 表。

示例 1:插入一条完整的新学生记录 (使用语法 1)

假设 Students 表的列顺序是 StudentID, FirstName, LastName, Age, Major, EnrollmentDate

sql
INSERT INTO Students VALUES (106, '八', '孙', 20, '电子工程', '2022-09-01');

  • 解释: 这会将一个新行添加到 Students 表中,各个值按照列的顺序对应。

示例 2:插入一条新学生记录,只提供部分信息 (使用语法 2)

假设我们暂时不知道某个学生的专业和入学日期。

sql
INSERT INTO Students (StudentID, FirstName, LastName, Age)
VALUES (107, '九', '周', 19);

  • 解释: 这将插入一个新行,StudentID 为 107,姓名和年龄也已赋值。MajorEnrollmentDate 列因为没有在括号中指定且提供了对应的值,并且我们在 CREATE TABLE 时没有给 MajorEnrollmentDate 设置 NOT NULL 约束(FirstNameLastNameNOT NULL,所以必须提供值),它们将变为 NULL (空值)。

重要提示:

  • 插入的值的数据类型必须与对应列的数据类型兼容。字符串值通常用单引号 ' 括起来,数字不需要。日期和时间值通常也用单引号括起来,格式取决于数据库系统和设置,但 'YYYY-MM-DD' 是常见的日期格式。
  • 如果列有 NOT NULL 约束,你在插入时必须为它提供一个非 NULL 的值。
  • 如果列是 PRIMARY KEY 且数据类型是整数,有些数据库系统(如 SQLite)会自动生成唯一值,你可以在 INSERT 时忽略这列,或者为它提供 NULL 值(具体行为取决于数据库系统和表定义)。但在我们的 Students 表中,我们明确要求提供了 StudentID 的值。

4.3 UPDATE:更新数据 (Update)

UPDATE 语句用于修改表中已存在的记录。

基本语法:

sql
UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition; -- **非常重要!**

  • UPDATE table_name: 指定要更新哪个表。
  • SET column1 = value1, ...: 指定要修改哪些列,以及它们的新值。可以同时更新多个列,用逗号分隔。
  • WHERE condition: (可选,但通常必选) 指定要更新哪些行。只有满足 condition 的行才会被修改。

实践演练与示例:

继续使用 Students 表。

示例 1:将某个学生的专业从“物理”更新为“应用物理”

假设学生ID为 102 的专业是物理。

sql
UPDATE Students
SET Major = '应用物理'
WHERE StudentID = 102;

  • 解释: 这条语句会找到 StudentID 等于 102 的那一行,然后将其 Major 列的值更新为 '应用物理'

示例 2:将所有“计算机科学”专业的学生的年龄增加 1 岁

sql
UPDATE Students
SET Age = Age + 1
WHERE Major = '计算机科学';

  • 解释: 这会找到所有 Major'计算机科学' 的行,并将它们的 Age 值在原有基础上加 1。

示例 3:更新多个列

将学生ID为 103 的年龄更新为 21,并将专业更新为“软件工程”。

sql
UPDATE Students
SET Age = 21, Major = '软件工程'
WHERE StudentID = 103;

  • 解释: 使用逗号分隔,可以同时更新多个列。

示例 4:🚨🚨🚨 更新所有行的年龄(请谨慎执行!) 🚨🚨🚨

sql
UPDATE Students
SET Age = Age + 1; -- **注意:没有 WHERE 子句!**

  • 解释: 极其危险! 这条语句会更新 Students 表中的所有行,将所有学生的年龄都加 1。在实际操作中,除非你确定要对全表进行修改,永远不要省略 WHERE 子句! 如果不小心执行了没有 WHEREUPDATE,可能会导致数据大面积错误,且难以恢复。

再次强调: 在编写 UPDATE 语句时,务必仔细检查 WHERE 子句,确保它准确地选择了你想要修改的行。

4.4 DELETE FROM:删除数据 (Delete)

DELETE FROM 语句用于从表中删除已存在的记录。

基本语法:

sql
DELETE FROM table_name
WHERE condition; -- **非常重要!**

  • DELETE FROM table_name: 指定要从哪个表中删除数据。
  • WHERE condition: (可选,但通常必选) 指定要删除哪些行。只有满足 condition 的行才会被删除。

实践演练与示例:

继续使用 Students 表。

示例 1:删除学生ID为 106 的学生记录

sql
DELETE FROM Students
WHERE StudentID = 106;

  • 解释: 这会找到 StudentID 等于 106 的那一行,并将其从表中删除。

示例 2:删除所有年龄小于 20 岁的学生记录

sql
DELETE FROM Students
WHERE Age < 20;

  • 解释: 这会删除所有年龄小于 20 的学生行。

示例 3:🚨🚨🚨 删除表中的所有数据(请谨慎执行!) 🚨🚨🚨

sql
DELETE FROM Students; -- **注意:没有 WHERE 子句!**

  • 解释: 极其危险! 这条语句会删除 Students 表中的所有行。表结构本身(列定义、约束等)会保留,但数据将全部丢失。这通常用于清空表。在实际操作中,除非你确定要清空整个表,永远不要省略 WHERE 子句! 不小心执行可能导致所有数据丢失。

再次强调: 在编写 DELETE 语句时,务必仔细检查 WHERE 子句,确保它准确地选择了你想要删除的行。对于重要数据,执行 DELETE 前最好先用相同的 WHERE 条件执行一个 SELECT 语句,看看会选中哪些行,以确认无误。

5. 数据定义语句 (DDL)

除了操作数据 (CRUD),SQL 还用于定义和管理数据库对象的结构,这部分语句被称为数据定义语言 (Data Definition Language, DDL)。最常见的 DDL 语句包括 CREATE, ALTER, DROP

5.1 CREATE TABLE:创建表

我们已经在前面创建 Students 表时演示了 CREATE TABLE 的基本用法。这里我们再详细回顾一下语法和常用的数据类型。

基本语法:

sql
CREATE TABLE table_name (
column1 datatype [constraints],
column2 datatype [constraints],
...
);

  • CREATE TABLE table_name: 指定要创建的表名。
  • column datatype [constraints]: 定义列的名称、数据类型以及可选的约束。

常用数据类型介绍:

不同的数据库系统支持的数据类型略有差异,但以下类型是通用的或具有相似概念:

  • 整型: INT, INTEGER, SMALLINT, BIGINT (用于存储整数,根据类型不同支持的范围大小不同)。
  • 浮点型: FLOAT, DOUBLE, REAL (用于存储浮点数)。
  • 定点型/精确数值: DECIMAL(p, s), NUMERIC(p, s) (用于存储需要精确计算的数值,如货币。p 是总位数,s 是小数点后位数)。
  • 字符串/文本: VARCHAR(length) (变长字符串,需要指定最大长度 length),CHAR(length) (定长字符串),TEXT (长文本)。
  • 日期和时间: DATE (存储日期,如 ‘2023-10-26’),TIME (存储时间,如 ’14:30:00′),DATETIME/TIMESTAMP (存储日期和时间)。
  • 布尔型: BOOLEAN/BOOL (存储真或假值)。
  • 空值: NULL (表示缺失或未知的值,不是零或空字符串)。

常用列约束 (Constraints):

  • NOT NULL: 该列的值不能为 NULL。
  • UNIQUE: 该列的所有值必须是唯一的(可以有多个 NULL 值,取决于数据库系统)。
  • PRIMARY KEY: 该列是主键。主键用于唯一标识表中的每一行,它集成了 NOT NULLUNIQUE 的特性。一个表通常只有一个主键,可以是单列或多列组合。
  • FOREIGN KEY: 外键。用于建立两个表之间的关系,指向另一个表的主键(或其他具有唯一约束的列)。我们将在 JOIN 部分稍微触及这个概念。
  • DEFAULT value: 为该列设置一个默认值,如果在插入新行时没有为该列指定值,将使用默认值。
  • CHECK condition: 定义一个检查约束,确保该列的值满足指定的条件。

示例:创建一个更详细的 Courses 表

sql
CREATE TABLE Courses (
CourseID INTEGER PRIMARY KEY,
CourseName VARCHAR(100) NOT NULL UNIQUE, -- 课程名不能为空且必须唯一
Credits INT CHECK (Credits > 0), -- 学分必须是大于0的整数
Department VARCHAR(50) DEFAULT 'General' -- 如果不指定,默认部门为 'General'
);

  • 解释: 创建了一个 Courses 表,包含课程ID(主键)、课程名(非空且唯一)、学分(必须大于0)和部门(默认值为 ‘General’)。

5.2 ALTER TABLE:修改表结构

ALTER TABLE 语句用于修改表的结构,例如添加、删除或修改列。

基本语法 (添加列):

sql
ALTER TABLE table_name
ADD COLUMN column_name datatype [constraints];

基本语法 (删除列):

sql
ALTER TABLE table_name
DROP COLUMN column_name;

  • 注意:修改列的数据类型或约束的语法在不同数据库系统中有较大差异,这里不做详细介绍,主要关注添加和删除列。

实践演练与示例:

继续使用 Students 表。

示例 1:向 Students 表添加一个“Email”列

sql
ALTER TABLE Students
ADD COLUMN Email VARCHAR(255);

  • 解释:Students 表中添加一个名为 Email 的列,数据类型为 VARCHAR(255)。现有行的 Email 列将被设置为 NULL

示例 2:向 Students 表添加一个“GPA”列,允许小数

sql
ALTER TABLE Students
ADD COLUMN GPA REAL;

  • 解释: 添加一个 GPA 列,数据类型为 REAL (浮点数)。

示例 3:删除 Students 表中的“Major”列

sql
ALTER TABLE Students
DROP COLUMN Major;

  • 解释:Students 表中删除 Major 列。注意,这会丢失该列中的所有数据。

5.3 DROP TABLE:删除表

DROP TABLE 语句用于完全删除一个表,包括表结构和所有数据。

基本语法:

sql
DROP TABLE table_name;

实践演练与示例:

示例:删除 Courses 表

sql
DROP TABLE Courses;

  • 解释: 这会从数据库中永久删除 Courses 表及其所有数据。

🚨🚨🚨 警告: DROP TABLE 是一个破坏性操作,一旦执行,表及其数据将很难恢复。请务必谨慎使用,特别是在生产环境中!

6. 进阶查询技巧

掌握了基本的 CRUD 和 DDL 语句后,我们可以学习如何更精确、更灵活地查询数据。

6.1 WHERE 子句详解:条件筛选

WHERE 子句是 SELECT, UPDATE, DELETE 语句中用于指定筛选条件的强大工具。它允许你根据一个或多个条件来选择或操作特定的行。

基本语法回顾:

sql
SELECT column1, column2, ...
FROM table_name
WHERE condition; -- 筛选条件在这里

常用的筛选条件构成:

condition 通常由一个或多个表达式和运算符组成。

a) 比较运算符:

用于比较列的值与另一个值或列的值。

  • =:等于
  • !=<>:不等于 (不同数据库系统可能使用其中一个)
  • >:大于
  • <:小于
  • >=:大于或等于
  • <=:小于或等于

示例:

sql
SELECT * FROM Students WHERE Age > 20; -- 查询年龄大于20岁的学生
SELECT FirstName, LastName FROM Students WHERE Major = '计算机科学'; -- 查询专业是计算机科学的学生
SELECT * FROM Students WHERE EnrollmentDate < '2022-01-01'; -- 查询2022年之前入学的学生
SELECT * FROM Students WHERE StudentID <> 101; -- 查询学生ID不等于101的学生

b) 逻辑运算符:

用于组合多个条件。

  • AND: 当所有连接的条件都为真时,整个条件为真。
  • OR: 当任一连接的条件为真时,整个条件为真。
  • NOT: 对连接的条件取反。

示例:

sql
SELECT * FROM Students WHERE Age >= 20 AND Major = '计算机科学'; -- 查询年龄大于等于20岁且专业是计算机科学的学生
SELECT * FROM Students WHERE Major = '物理' OR Major = '数学'; -- 查询专业是物理或数学的学生
SELECT * FROM Students WHERE NOT Major = '计算机科学'; -- 查询专业不是计算机科学的学生 (等同于 Major <> '计算机科学')
SELECT * FROM Students WHERE (Age > 20 AND Major = '物理') OR Age < 19; -- 使用括号组合复杂的逻辑

c) 范围查询 (BETWEEN):

用于判断一个值是否在某个范围内(包含边界)。

sql
SELECT * FROM Students WHERE Age BETWEEN 20 AND 22; -- 查询年龄在20到22岁之间(含20和22)的学生
SELECT * FROM Students WHERE EnrollmentDate BETWEEN '2022-01-01' AND '2022-12-31'; -- 查询2022年入学的学生

d) 集合查询 (IN):

用于判断一个值是否在一个给定的值列表内。

sql
SELECT * FROM Students WHERE Major IN ('计算机科学', '数学', '电子工程'); -- 查询专业是计算机科学、数学或电子工程的学生 (等同于使用多个 OR)
SELECT * FROM Students WHERE StudentID NOT IN (101, 103, 105); -- 查询学生ID不是101、103或105的学生

e) 模糊匹配 (LIKE):

用于在字符串列中进行模式匹配。需要配合通配符使用:

  • %: 代表任意零个或多个字符。
  • _: 代表任意一个字符。

sql
SELECT * FROM Students WHERE LastName LIKE '张%'; -- 查询姓“张”的学生
SELECT * FROM Students WHERE FirstName LIKE '%三'; -- 查询名以“三”结尾的学生
SELECT * FROM Students WHERE CourseName LIKE '%数据%'; -- 查询课程名中包含“数据”二字的课程 (假设有 Courses 表)
SELECT * FROM Students WHERE StudentID LIKE '10_'; -- 查询学生ID是10几的学生 (如 101, 102, ..., 109)
SELECT * FROM Students WHERE FirstName LIKE '_三'; -- 查询名是两个字且第二个字是“三”的学生 (如“小三”)

f) 空值判断 (IS NULL, IS NOT NULL):

用于判断一个列的值是否为 NULL注意:不能使用 =!= 来判断 NULL

sql
SELECT * FROM Students WHERE Major IS NULL; -- 查询专业为空的学生
SELECT * FROM Students WHERE Email IS NOT NULL; -- 查询Email不为空的学生

6.2 ORDER BY 子句:排序结果

ORDER BY 子句用于对查询结果集进行排序。默认是升序。

基本语法:

sql
SELECT column1, column2, ...
FROM table_name
WHERE condition
ORDER BY column1 [ASC|DESC], column2 [ASC|DESC], ...;

  • ORDER BY: 关键字,表示要排序。
  • column1, column2, ...: 指定用于排序的列。可以按多个列排序,优先级从左到右。
  • ASC: 升序 (Ascending),默认值。
  • DESC: 降序 (Descending)。

实践演练与示例:

sql
SELECT * FROM Students ORDER BY Age; -- 按年龄升序排序所有学生
SELECT * FROM Students ORDER BY EnrollmentDate DESC; -- 按入学日期降序排序所有学生 (最近入学的排在前面)
SELECT FirstName, LastName, Major, Age FROM Students ORDER BY Major ASC, Age DESC; -- 先按专业升序排序,如果专业相同,则按年龄降序排序

6.3 LIMIT / TOP 子句:限制结果数量

在处理大量数据时,有时我们只需要查看前面几条或指定范围的记录。可以使用 LIMITTOP 子句。不同数据库系统使用的关键字不同:

  • 标准 SQL, MySQL, PostgreSQL, SQLite: 使用 LIMIT
  • SQL Server, MS Access: 使用 TOP

语法 (LIMIT):

sql
SELECT column1, column2, ...
FROM table_name
WHERE condition
ORDER BY column
LIMIT number; -- 获取前 number 行

LIMIT offset, number (获取从 offset 开始的 number 行,用于分页,offset 从 0 或 1 开始取决于数据库)

语法 (TOP):

sql
SELECT TOP number column1, column2, ...
FROM table_name
WHERE condition
ORDER BY column; -- SQL Server 的 TOP 通常放在 SELECT 后面

实践演练与示例 (以 LIMIT 为例):

sql
SELECT * FROM Students LIMIT 3; -- 获取表中的前3行 (不保证顺序,通常需要配合 ORDER BY)
SELECT * FROM Students ORDER BY Age DESC LIMIT 5; -- 查询年龄最大的5个学生
SELECT * FROM Students ORDER BY StudentID LIMIT 5 OFFSET 5; -- 查询学生ID排序后的第6到第10个学生 (从偏移量5开始,取5个)

6.4 DISTINCT 关键字:去除重复行

DISTINCT 关键字用于去除结果集中的重复行,只返回唯一的组合。

基本语法:

sql
SELECT DISTINCT column1, column2, ...
FROM table_name
WHERE condition;

  • DISTINCT: 放在 SELECT 后面,作用于 SELECT 后面的所有列的组合。

实践演练与示例:

sql
SELECT Major FROM Students; -- 可能返回重复的专业,如:计算机科学, 物理, 计算机科学, 数学, 计算机科学
SELECT DISTINCT Major FROM Students; -- 返回唯一的专业列表:计算机科学, 物理, 数学
SELECT DISTINCT Age, Major FROM Students; -- 返回年龄和专业的唯一组合

7. 聚合函数与分组

仅仅查询原始数据往往不够,我们经常需要对数据进行统计分析,比如计算总数、平均值、最大/最小值等。这就需要用到聚合函数

有时候,我们还需要对数据进行分组统计,比如计算每个专业的学生人数,或者每个专业的平均年龄。这时就需要用到 GROUP BY 子句。

7.1 常用聚合函数:

聚合函数作用于一组行,并返回单个值。

  • COUNT(column): 统计指定列中非 NULL 值的行数。COUNT(*) 统计所有行(包括 NULL 值的行)。
  • SUM(column): 计算指定列的总和(仅适用于数值类型)。
  • AVG(column): 计算指定列的平均值(仅适用于数值类型)。
  • MIN(column): 获取指定列的最小值。
  • MAX(column): 获取指定列的最大值。

实践演练与示例:

sql
SELECT COUNT(*) FROM Students; -- 统计学生总人数 (所有行)
SELECT COUNT(Major) FROM Students; -- 统计有专业信息的学生人数 (Major列非NULL的行)
SELECT AVG(Age) FROM Students; -- 计算学生的平均年龄
SELECT MIN(Age) FROM Students; -- 获取最小年龄
SELECT MAX(EnrollmentDate) FROM Students; -- 获取最晚的入学日期
SELECT SUM(Credits) FROM Courses; -- 计算所有课程的总学分 (假设有 Courses 表)

7.2 GROUP BY 子句:按列分组

GROUP BY 子句用于将结果集按照一个或多个列进行分组。聚合函数通常与 GROUP BY 一起使用,以便对每个组而不是整个结果集进行计算。

基本语法:

sql
SELECT column_to_group, aggregate_function(column_to_aggregate), ...
FROM table_name
WHERE condition
GROUP BY column_to_group, ...
ORDER BY column_to_group, ...;

  • GROUP BY column_to_group: 指定用于分组的列。所有具有相同值的行将被分到同一个组。
  • SELECT 列表中,除了聚合函数外,只能包含 GROUP BY 子句中指定的列。

实践演练与示例:

sql
SELECT Major, COUNT(*) AS NumberOfStudents -- AS 为列取别名,方便阅读
FROM Students
GROUP BY Major;

  • 解释: 这会按照 Major 列将学生分组,然后统计每个组(每个专业)的学生人数。结果可能是:
    Major NumberOfStudents
    ------------- ----------------
    计算机科学 3
    物理 1
    数学 1
    电子工程 1
    NULL 1

    (如果有的学生专业是 NULL,会单独分为一组)

sql
SELECT Major, AVG(Age) AS AverageAge
FROM Students
GROUP BY Major;

  • 解释: 统计每个专业的平均年龄。

sql
SELECT EnrollmentDate, COUNT(*) AS NewStudentsCount
FROM Students
GROUP BY EnrollmentDate
ORDER BY EnrollmentDate;

  • 解释: 统计每个入学日期的新生人数,并按日期排序。

7.3 HAVING 子句:筛选分组

WHERE 子句用于在分组之前筛选原始行,而 HAVING 子句用于在分组之后筛选分组结果。聚合函数不能用于 WHERE 子句,但可以用于 HAVING 子句。

基本语法:

sql
SELECT column_to_group, aggregate_function(column_to_aggregate), ...
FROM table_name
WHERE condition -- (可选) 先筛选原始行
GROUP BY column_to_group, ...
HAVING group_condition -- (可选) 再筛选分组结果
ORDER BY column_to_group, ...;

实践演练与示例:

sql
-- 查询学生人数多于1个的专业及其人数
SELECT Major, COUNT(*) AS NumberOfStudents
FROM Students
GROUP BY Major
HAVING COUNT(*) > 1;

  • 解释: 先按专业分组并计算各专业人数,然后只保留人数大于 1 的分组。

sql
-- 查询平均年龄大于20岁的专业及其平均年龄
SELECT Major, AVG(Age) AS AverageAge
FROM Students
GROUP BY Major
HAVING AVG(Age) > 20;

  • 解释: 先按专业分组并计算各专业平均年龄,然后只保留平均年龄大于 20 的分组。

WHEREHAVING 的区别总结:

  • WHEREGROUP BY 之前执行,用于筛选原始行。它不能包含聚合函数。
  • HAVINGGROUP BY 之后执行,用于筛选分组的结果。它可以包含聚合函数。

8. 连接多个表 (JOIN 入门)

在实际应用中,数据通常分散在多个相关的表中,而不是全部挤在一个大表中。例如,学生信息在一个表,课程信息在另一个表,学生选课记录在第三个表。关系型数据库的强大之处在于能够通过表之间的“关系”将这些数据有效地组合起来。JOIN 语句就是用来实现这个功能的。

为什么需要连接表?

考虑一下,如果要在学生选课记录中显示学生的姓名和课程名称,而不是只有学生ID和课程ID,我们就需要:

  1. 从“选课记录表”获取学生ID和课程ID。
  2. 根据学生ID去“学生表”查找对应的学生姓名。
  3. 根据课程ID去“课程表”查找对应的课程名称。

JOIN 语句能够一次性完成这个“查找”和“组合”的过程。

表之间的关系通常通过主键 (PRIMARY KEY)外键 (FOREIGN KEY) 来建立。外键是某个表中的一列或一组列,它们的值指向另一个表的主键。例如,Enrollments (选课记录) 表可能有 StudentIDCourseID 列,它们分别是指向 Students 表的 StudentID 主键和 Courses 表的 CourseID 主键的外键。

8.1 INNER JOIN:内连接

内连接是最常用的连接类型。它返回两个表中在连接列上匹配成功的行。如果某个行在其中一个表中没有匹配项,则不会出现在结果中。

基本语法:

sql
SELECT column_list
FROM table1
INNER JOIN table2 ON table1.column = table2.column;

  • SELECT column_list: 选择你想要显示的列。为了避免歧义,通常使用 table_name.column_name 的形式指定列属于哪个表。
  • FROM table1: 指定第一个表。
  • INNER JOIN table2: 指定要与 table1 进行内连接的第二个表。
  • ON table1.column = table2.column: 指定连接条件。这通常是两个表中具有相同意义且存在对应关系的列(例如,一个表的外键与另一个表的主键)。

示例:

假设我们有一个 Enrollments (选课记录) 表,包含 EnrollmentID, StudentID, CourseID, Grade 列,其中 StudentID 是外键指向 Students 表的 StudentIDCourseID 是外键指向 Courses 表的 CourseID

“`sql
— 创建 Enrollments 表
CREATE TABLE Enrollments (
EnrollmentID INTEGER PRIMARY KEY,
StudentID INTEGER,
CourseID INTEGER,
Grade VARCHAR(10),
FOREIGN KEY (StudentID) REFERENCES Students(StudentID), — 假设 Students 表已存在
FOREIGN KEY (CourseID) REFERENCES Courses(CourseID) — 假设 Courses 表已存在
);

— 添加一些选课数据
INSERT INTO Enrollments (EnrollmentID, StudentID, CourseID, Grade) VALUES (1, 101, 1, ‘A’); — 张三 选课ID 1 (假设课程ID 1 是 数据库原理)
INSERT INTO Enrollments (EnrollmentID, StudentID, CourseID, Grade) VALUES (2, 101, 2, ‘B’); — 张三 选课ID 2 (假设课程ID 2 是 算法导论)
INSERT INTO Enrollments (EnrollmentID, StudentID, CourseID, Grade) VALUES (3, 102, 1, ‘C’); — 李四 选课ID 1
INSERT INTO Enrollments (EnrollmentID, StudentID, CourseID, Grade) VALUES (4, 103, 3, ‘A-‘); — 王五 选课ID 3 (假设课程ID 3 是 操作系统)
— 假设学生 104 (赵六) 和 105 (钱七) 还没有选课记录
— 假设课程 ID 4 (例如 软件工程) 还没有学生选
“`

现在,我们来查询选课记录,并显示学生的姓名和课程名称:

sql
SELECT
Students.FirstName,
Students.LastName,
Courses.CourseName,
Enrollments.Grade
FROM
Enrollments -- 从选课记录表开始
INNER JOIN
Students ON Enrollments.StudentID = Students.StudentID -- 连接学生表,条件是选课表的 StudentID 等于学生表的 StudentID
INNER JOIN
Courses ON Enrollments.CourseID = Courses.CourseID; -- 连接课程表,条件是选课表的 CourseID 等于课程表的 CourseID

  • 解释: 这条语句将 Enrollments, Students, Courses 三个表连接起来。它会找到 Enrollments 表中的每一行,然后根据 StudentID 去匹配 Students 表,根据 CourseID 去匹配 Courses 表。只有当在三个表中都能找到对应的匹配项时,才会返回结果行。结果将包含学生的姓名、课程名称和该学生在该课程中的成绩。

    例如,Enrollments 表中的 (1, 101, 1, 'A') 会与 Students 表中 StudentID = 101 的行(张三)以及 Courses 表中 CourseID = 1 的行(数据库原理)匹配,最终产生一行结果:, , 数据库原理, A

    如果学生 104 没有选课记录,或者课程 ID 4 没有被任何学生选择,涉及它们的行就不会出现在 INNER JOIN 的结果中。

连接是关系型数据库查询的核心,也是 SQL 的难点之一。这里只介绍了最基本的内连接,还有外连接 (LEFT JOIN, RIGHT JOIN, FULL JOIN) 等更复杂的连接方式,用于处理不完全匹配的情况。

9. 总结与下一步学习

恭喜你!如果你已经阅读到这里,并尝试了其中的例子,你已经掌握了 SQL 的核心基础:

  • 理解了数据库、表、列、行的基本概念。
  • 学会了如何使用 SELECT 查询数据,包括选择特定列和使用 *
  • 掌握了使用 INSERT 添加新数据。
  • 了解了使用 UPDATE 修改数据,并记住了 WHERE 子句的重要性。
  • 学会了使用 DELETE 删除数据,并记住了 WHERE 子句的重要性。
  • 学会了使用 CREATE TABLE 定义表结构,包括常用数据类型和主键。
  • 了解了如何使用 ALTER TABLE 修改表结构(添加/删除列)。
  • 学会了使用 DROP TABLE 删除表(并记住了其风险)。
  • 深入学习了 WHERE 子句,掌握了各种条件筛选的方法(比较、逻辑、范围、集合、模糊匹配、空值判断)。
  • 学会了使用 ORDER BY 对结果进行排序。
  • 了解了使用 LIMITTOP 限制结果数量。
  • 学会了使用 DISTINCT 去除重复行。
  • 掌握了常用的聚合函数 (COUNT, SUM, AVG, MIN, MAX)。
  • 学会了使用 GROUP BY 进行分组统计,并理解了 HAVINGWHERE 的区别。
  • 初步了解了关系型数据库如何连接多个表,并掌握了最基本的 INNER JOIN 用法。

这篇指南覆盖了 SQL 中最常用、最基础但也是最重要的语句。掌握了这些,你已经具备了与数据库进行基本交流的能力。

下一步学习方向:

SQL 的世界远不止这些,你可以继续学习:

  1. 更高级的连接: LEFT JOIN, RIGHT JOIN, FULL JOIN 等,处理更复杂的表关联场景。
  2. 子查询 (Subquery): 在一个查询中使用另一个查询的结果。
  3. 联合查询 (UNION): 合并多个 SELECT 语句的结果集。
  4. 窗口函数 (Window Functions): 进行更复杂的分析和排名。
  5. 索引 (Index): 理解如何通过创建索引来优化查询性能。
  6. 事务 (Transaction): 学习如何确保一系列数据库操作要么全部成功,要么全部失败,保证数据一致性。
  7. 特定数据库系统的特性: 深入了解你正在使用的具体数据库系统(如 MySQL, PostgreSQL, SQL Server)的独特功能和优化技巧。

最后的建议:

  • 持续实践: 找一个实际的数据集或自己创建数据,不断练习编写各种查询。遇到问题多查阅文档和在线资源。
  • 理解数据: 在编写查询之前,花时间理解你的数据是什么、表之间有什么关系,这将帮助你写出正确的 SQL 语句。
  • 谨慎操作: 在执行 UPDATE, DELETE, DROP TABLE 等修改或删除数据的语句时,务必再三确认,最好先在测试环境中验证。

祝你在 SQL 的学习旅程中一切顺利!数据世界的精彩正等待着你去探索。


发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部