欢迎来到交互式 SQL 教程!您无需安装任何软件,所有操作都在浏览器中完成。
我们为您预加载了三个示例表:employees, products, 和 orders。
表结构 (带中文注释):
id - 员工IDname - 姓名department - 所在部门salary - 薪水hire_date - 入职日期id - 商品IDname - 商品名称category - 类别price - 价格stock - 库存数量order_id - 订单IDproduct_id - 关联的商品IDemployee_id - 关联的员工ID (销售员)quantity - 订购数量order_date - 下单日期点击“运行”来执行 SQL,或“重置数据库”恢复初始数据。
本节介绍 SQL 中用于检索和操作数据的基本子句。
ORDER BY:排序结果集ORDER BY 子句用于对 SELECT 语句返回的结果集进行排序。
ORDER BY 列1 [ASC|DESC], 列2 [ASC|DESC], ...ASC (Ascending) 表示升序,是默认的排序方式。DESC (Descending) 表示降序,会以相反的顺序排序。示例:SELECT name, salary FROM employees ORDER BY salary DESC;
解释:此查询从 employees(员工)表中选择 name(姓名)和 salary(薪水)两列。ORDER BY salary DESC 子句会根据 salary 列的值进行降序排序,这意味着薪水较高的员工会首先显示。这有助于快速找出薪水最高的员工。
LIMIT 和 OFFSET:分页显示LIMIT 和 OFFSET 子句通常一起使用,用于实现分页功能,允许您从结果集的特定起始点检索指定数量的行。
LIMIT 数量:限制返回的行数。OFFSET 起始点:跳过指定数量的行,从跳过后的位置开始检索。示例1:SELECT * FROM products ORDER BY price DESC LIMIT 3;
解释:此查询从 products(商品)表中选择所有列。它首先根据 price(价格)列进行降序排序(最贵的产品在前)。然后,LIMIT 3 将输出限制为仅显示价格最高的3件产品。这对于查找最昂贵的商品非常有用。
示例2:SELECT * FROM products ORDER BY price DESC LIMIT 3 OFFSET 3;
解释:与上一个示例类似,此查询也按价格降序排序产品。但是,OFFSET 3 告诉数据库跳过前3行(即跳过最贵的3件产品)。然后,LIMIT 3 检索接下来的3行。这实际上为您提供了第4、5、6件最昂贵的产品,展示了如何获取结果的“下一页”。
AS (别名):为列或表指定临时名称AS 关键字用于在查询中为列或表指定一个临时的名称(别名)。这可以使查询结果更具可读性,并能简化复杂的查询。
SELECT 列名 AS 别名 FROM 表名;SELECT 表别名.列名 FROM 表名 AS 表别名; (表别名常用于多表连接中,以缩短表名并避免歧义)。示例:SELECT name AS employee_name, salary AS monthly_salary FROM employees;
解释:此查询从 employees 表中选择 name 和 salary 列。name AS employee_name 将输出中的 name 列重命名为 employee_name,salary AS monthly_salary 将 salary 重命名为 monthly_salary。原始表中的列名保持不变;此别名仅对当前查询的结果集有效;这提高了输出的清晰度,尤其当列名模糊或过短时。
本节介绍聚合函数以及 GROUP BY 和 HAVING 子句,它们对于汇总和分析数据至关重要。
聚合函数对一组行执行计算,并返回一个单一的汇总值。常见的聚合函数包括:
COUNT():计算行数。SUM():计算数值列的总和。AVG():计算数值列的平均值。MIN():查找列中的最小值。MAX():查找列中的最大值。示例1:SELECT COUNT(*) AS total_employees FROM employees;
解释:此查询使用 COUNT(*) 来计算 employees(员工)表中的所有行,从而得到员工的总数。AS total_employees 为结果列分配了一个更具描述性的别名。
示例2:SELECT AVG(salary) AS avg_salary FROM employees;
解释:此查询使用 AVG(salary) 计算所有员工 salary(薪水)列的平均值。结果被别名为 avg_salary。
GROUP BY:对行进行分组GROUP BY 子句将指定列中具有相同值的行分组为汇总行。它几乎总是与聚合函数一起使用。当您使用聚合函数时,SELECT 语句中任何未聚合的列都必须包含在 GROUP BY 子句中。
示例:SELECT department, COUNT(*) AS num_employees FROM employees GROUP BY department;
解释:此查询根据 department(部门)对 employees 表进行分组。对于每个唯一的部门,COUNT(*) 计算该部门中的员工数量。结果显示每个部门及其员工数量。这有助于了解员工在不同部门的分布情况。
HAVING:过滤分组后的结果HAVING 子句用于过滤 GROUP BY 子句的结果。WHERE 子句在分组之前过滤单个行,而 HAVING 子句在聚合之后过滤分组。
示例:SELECT department, AVG(salary) AS avg_salary FROM employees GROUP BY department HAVING AVG(salary) > 80000;
解释:此查询首先按 department 对员工进行分组,并计算每个部门的平均 salary。然后,HAVING AVG(salary) > 80000 子句过滤这些分组,只显示平均薪水大于80,000的部门。这使您能够识别高薪部门。
关系型数据库通常将相关数据存储在多个表中,以减少冗余并提高数据完整性。连接(Joins)用于根据表之间的相关列来组合来自两个或更多表的行。
INNER JOIN:内连接INNER JOIN 只返回两个表中都存在匹配值的行。如果一个表中的行在另一个表中没有匹配的行,则该行将从结果中排除。
示例:SELECT e.name AS employee, p.name AS product FROM orders o JOIN employees e ON o.employee_id = e.id JOIN products p ON o.product_id = p.id;
解释:此查询结合了三个表的数据:orders(别名为 o)、employees(别名为 e)和 products(别名为 p)。
JOIN employees e ON o.employee_id = e.id:这部分根据 orders 表中的 employee_id 与 employees 表中的 id 匹配来连接 orders 和 employees 表。这会将每个订单与其对应的员工关联起来。JOIN products p ON o.product_id = p.id:这部分接着将结果与 products 表连接,根据 orders 表中的 product_id 与 products 表中的 id 匹配。这会将每个订单与其订购的产品关联起来。SELECT 语句然后检索每个匹配订单的员工姓名和产品名称。结果显示“谁订购了什么”。
LEFT JOIN (或 LEFT OUTER JOIN):左连接LEFT JOIN 返回左表中的所有行,以及右表中匹配的行。如果右表中没有匹配的行,则右表列的值将返回 NULL。
示例:SELECT e.name, o.order_id FROM employees e LEFT JOIN orders o ON e.id = o.employee_id;
解释:此查询将 employees 表(左表,别名为 e)与 orders 表(右表,别名为 o)结合。
ON e.id = o.employee_id:连接条件根据 employee_id 匹配员工和他们的订单。LEFT JOIN 确保所有员工都包含在结果中,即使他们没有下过任何订单。对于没有匹配订单的员工,orders 表中的 order_id 列将显示 NULL。此查询有效地显示了“所有员工及其订单”,包括那些没有订单的员工。
本节深入探讨更复杂的查询技术,这些技术能够实现强大的数据操作和分析。
子查询是嵌套在另一个 SQL 查询内部的查询。子查询可以在 SELECT、FROM、WHERE 或 HAVING 子句中使用。它们通常用于返回单个值或一组值,然后供外部查询使用。
示例:SELECT name, salary FROM employees WHERE salary > (SELECT AVG(salary) FROM employees);
解释:此查询使用子查询 (SELECT AVG(salary) FROM employees) 首先计算所有员工的平均薪水。外部查询然后选择 salary 大于此计算出的平均薪水的员工的 name(姓名)和 salary(薪水)。这有效地找出了“高于平均薪水”的员工。
CASE 语句:条件逻辑CASE 语句是一种条件表达式,允许您根据不同的条件定义不同的输出。它类似于编程中的 if-then-else 逻辑。
CASE
WHEN condition1 THEN result1
WHEN condition2 THEN result2
...
ELSE resultN
END
示例:SELECT name, salary, CASE WHEN salary > 100000 THEN '高级' WHEN salary > 70000 THEN '中级' ELSE '初级' END AS salary_level FROM employees;
解释:此查询根据员工的 salary(薪水)为每位员工分配一个“薪水评级”。
salary 大于 100,000,则 salary_level 为 '高级'。salary 大于 70,000(但不大于 100,000),则为 '中级'。这展示了如何在单个查询中根据多个条件对数据进行分类。
本节涵盖了用于修改表中数据的基本 SQL 命令:UPDATE 和 DELETE。这些是数据操作语言(DML)的一部分。
UPDATE:修改现有记录UPDATE 用于修改表中的现有记录。您需要指定要更新的表、要更改的列以及(可选地)使用 WHERE 子句来指定受影响的行。如果没有提供 WHERE 子句,表中的所有行都将被更新。
UPDATE 表名 SET 列1 = 值1, 列2 = 值2, ... WHERE 条件;示例:UPDATE products SET price = 28.00 WHERE name = '鼠标';
解释:此查询更新 products(商品)表。它将名为“鼠标”的产品价格设置为 28.00。WHERE name = '鼠标' 子句至关重要,因为它确保只更改特定产品的价格,而不是所有产品。运行此查询后,您可以执行 SELECT * FROM products; 来查看变化。
DELETE:删除记录DELETE 用于从表中删除现有记录。与 UPDATE 类似,WHERE 子句用于指定要删除的行。如果没有提供 WHERE 子句,表中的所有行都将被删除,从而清空该表。
DELETE FROM 表名 WHERE 条件;示例:DELETE FROM orders WHERE order_id = 3;
解释:此查询从 orders(订单)表中删除一条记录。WHERE order_id = 3 子句确保只删除 order_id 等于 3 的订单。
重要提示:DELETE 操作是不可逆的。一旦数据被删除,除非您有备份或在可以回滚的事务中,否则数据将丢失。教程中正确地警告:“注意: 操作无法撤销!可点击“重置数据库”恢复。”
本节涵盖了修改现有表结构的操作以及如何检查表模式。
ALTER TABLE:修改表结构ALTER TABLE 用于在现有表中添加、删除或修改列。它还可以用于在现有表上添加和删除各种约束。
ALTER TABLE 表名 ADD COLUMN 列名 数据类型 [约束];示例:ALTER TABLE employees ADD COLUMN status TEXT DEFAULT 'Active';
解释:此查询通过添加一个名为 status 的新列来修改 employees(员工)表。TEXT 数据类型表示它将存储文本,DEFAULT 'Active' 为插入到表中的任何新行以及现有行(取决于具体的 SQL 方言,SQLite 会将现有行设置为默认值)设置默认值为 'Active'。
运行后可执行 SELECT * FROM employees; 查看变化。
PRAGMA table_info()虽然 SELECT 用于检索数据,但您通常需要了解表的结构(模式),包括其列、数据类型和约束。在 SQLite(本教程通过 sql.js 使用)中,您可以使用 PRAGMA table_info()。
PRAGMA table_info(表名);示例:PRAGMA table_info('employees');
解释:此查询使用 SQLite 特有的 PRAGMA table_info() 命令来检索 employees 表结构的详细信息。结果将显示每列的名称、数据类型、是否可以为 NULL、其主键状态和默认值。这对于理解表的模式非常有用。
本节介绍更高级的 SQL 功能,这些功能能够实现复杂的数据分析和操作,通常可以简化原本非常复杂的查询。
WITH 语句CTE 使用 WITH 子句定义,是一个临时的、命名的结果集,您可以在单个 SELECT、INSERT、UPDATE 或 DELETE 语句中引用它。CTE 提高了复杂查询的可读性和可维护性,尤其是在处理递归查询或需要多次引用相同子查询时。
WITH cte_name (列1, 列2, ...) AS (
-- CTE 查询定义
SELECT ...
)
-- 使用 CTE 的主查询
SELECT ... FROM cte_name WHERE ...;
示例:
WITH HighSalaryEngineers AS (
SELECT id, name, salary
FROM employees
WHERE department = '工程部' AND salary > 100000
)
SELECT * FROM HighSalaryEngineers;
解释:此查询使用名为 HighSalaryEngineers 的 CTE,首先找出在“工程部”且 salary(薪水)大于 100,000 的员工。然后,主查询 SELECT * FROM HighSalaryEngineers; 从这个临时结果集中检索所有列。这通过将复杂的条件分解为可读的、命名的子查询,从而轻松地“查找高薪工程师”。
窗口函数对一组与当前行相关的表行执行计算。与聚合函数(如 SUM 或 COUNT)不同,窗口函数不会将行折叠成单个输出行;相反,它们为结果集中的每一行返回一个值。它们通常用于排名、移动平均或累积和。
函数名(表达式) OVER (PARTITION BY 列1 ORDER BY 列2 [ASC|DESC])PARTITION BY:将行分成组(分区)以供窗口函数独立应用。ORDER BY:对每个分区内的行进行排序。示例:
SELECT
name,
department,
salary,
RANK() OVER (PARTITION BY department ORDER BY salary DESC) as rank_in_department
FROM employees;
解释:此查询使用 RANK() 窗口函数,根据每个员工在其所属部门内的 salary(薪水)为其分配排名。
PARTITION BY department:将员工按部门分成不同的组。ORDER BY salary DESC:在每个部门内部,员工按 salary 降序排序。RANK() 然后根据此排序顺序为部门内的每个员工分配排名。如果两个员工的薪水相同,他们将获得相同的排名,并且下一个排名将被跳过(例如,1、2、2、4)。这使您能够“按部门薪水排名”。
以下是更多可供尝试的 SQL 查询示例: