SQL语法
资料库(Database)
定义:资料库是按照数据结构来组织、存储和管理数据的仓库。简单来说,它是一个长期存储在计算机内、有组织的、可共享的数据集合。这些数据可以是结构化的(如表格形式),也可以是非结构化的(如文档、图片等),但通常资料库主要处理结构化数据。
特点:
- 持久性:数据一旦存入资料库,就会长期保存,除非被显式删除或修改。
- 共享性:多个用户或应用程序可以同时访问和使用资料库中的数据。
- 独立性:数据的物理存储结构和逻辑结构可以相互独立,便于数据的维护和扩展。
- 安全性:资料库管理系统提供安全机制,保护数据不被未授权访问或篡改。
示例:一个企业的员工资料库可能包含员工的姓名、职位、薪资、联系方式等信息,这些信息以结构化的方式存储,便于查询和管理。
资料库管理系统(Database Management System, DBMS)
定义:资料库管理系统是一种用于管理资料库的软件系统。它提供了数据的定义、创建、查询、更新和管理等功能,使得用户能够方便地与资料库进行交互。
核心功能:
- 数据定义:允许用户定义资料库的结构,如表、字段、数据类型等。
- 数据操作:提供数据的增删改查(CRUD)操作。
- 数据控制:管理数据的访问权限,确保数据的安全性。
- 数据维护:包括数据的备份、恢复、优化等。
示例:MySQL、Oracle、SQL Server、PostgreSQL等都是常见的资料库管理系统。它们提供了图形化界面或命令行工具,让用户能够轻松地管理资料库。
SQL(Structured Query Language)
定义:SQL是一种用于访问和处理资料库的标准计算机语言。它专门设计用于与资料库进行通信,执行各种数据操作任务。
主要用途:
- 数据查询:使用SELECT语句从资料库中检索数据。
- 数据操作:使用INSERT、UPDATE、DELETE语句插入、更新和删除数据。
- 数据定义:使用CREATE、ALTER、DROP语句定义和修改资料库结构。
- 数据控制:使用GRANT、REVOKE语句管理数据的访问权限。
特点:
- 标准化:SQL是一种国际标准,被大多数资料库管理系统所支持。
- 易学易用:SQL语法相对简单,易于学习和使用。
- 强大功能:SQL提供了丰富的函数和操作符,支持复杂的数据查询和处理。
示例:以下是一个简单的SQL查询语句,用于从“员工”表中检索所有员工的姓名和职位:
SELECT 姓名, 职位 FROM 员工;
综上所述,资料库是存储数据的仓库,资料库管理系统是管理这些数据的软件系统,而SQL则是用于与资料库进行通信的标准语言。这三者共同构成了现代数据处理和分析的基础架构。
资料库中的键
在资料库(数据库)中,键(Key)是用于唯一标识表中记录或建立表之间关联的重要概念,它对于确保数据的完整性、一致性和高效查询至关重要。以下是资料库中常见的键类型及其详细说明:
1. 主键(Primary Key)
- 定义:主键是表中能够唯一标识每一行记录的一个或一组字段(列)。主键值必须唯一且不能为NULL。
- 作用:
- 确保每条记录的唯一性,防止重复数据。
- 作为其他表的外键,建立表与表之间的关联。
- 优化查询性能,因为主键通常会被索引。
- 示例:在学生表中,学生ID可以作为主键,因为每个学生都有唯一的ID。
2. 外键(Foreign Key)
- 定义:外键是表中一个或一组字段,它引用另一个表的主键,用于建立表与表之间的关联。
- 作用:
- 维护表之间的数据完整性,确保关联表中的数据一致性。
- 实现表之间的级联操作,如级联删除、级联更新等。
- 示例:在订单表中,客户ID可以作为外键,引用客户表中的主键,表示该订单属于哪个客户。
3. 候选键(Candidate Key)
- 定义:候选键是表中能够唯一标识每一行记录的一个或一组字段,且不包含多余的字段。一个表可以有多个候选键,但只能选择其中一个作为主键。
- 作用:
- 提供主键的备选方案,当主键不再适用时,可以选择其他候选键作为新的主键。
- 示例:在学生表中,除了学生ID外,身份证号也可能是一个候选键,因为它也能唯一标识每个学生。
4. 替代键(Alternate Key)
- 定义:替代键是候选键中未被选为主键的键。在主键确定后,其他候选键就成为替代键。
- 作用:
- 作为主键的备选,当主键需要变更时,可以选择替代键作为新的主键。
- 示例:在学生表中,如果选择了学生ID作为主键,那么身份证号就成为替代键。
5. 超键(Super Key)
- 定义:超键是表中能够唯一标识每一行记录的一个或一组字段的集合。超键可能包含多余的字段,即不一定是最小的键集合。
- 作用:
- 超键的概念用于理解键的层次结构,它包含了候选键和主键等更具体的键类型。
- 示例:在学生表中,学生ID和姓名组合可能是一个超键,但姓名本身可能不是唯一的,所以它不是候选键。
6. 复合键(Composite Key)
- 定义:复合键是由两个或多个字段组合而成的键,用于唯一标识表中的记录。
- 作用:
- 当单个字段无法唯一标识记录时,可以使用复合键。
- 示例:在订单明细表中,订单ID和产品ID的组合可以作为一个复合键,因为同一个订单中可能包含多个相同的产品,但订单ID和产品ID的组合是唯一的。
7. 自然键(Natural Key)
- 定义:自然键是表中已经存在的、具有业务意义的字段,它可以直接用作键。
- 作用:
- 自然键易于理解和使用,因为它与业务逻辑紧密相关。
- 示例:在学生表中,学生ID可以是一个自然键,因为它直接对应学生的唯一标识。
8. 代理键(Surrogate Key)
- 定义:代理键是表中没有业务意义的、人工生成的唯一标识符,通常用作主键。
- 作用:
- 当自然键不适合作为主键时(如可能变更、过长或复杂),可以使用代理键。
- 代理键可以提高数据库的性能和灵活性。
- 示例:在学生表中,可以添加一个自增的ID字段作为代理键,即使学生ID变更,也不会影响表之间的关联。
SQL语法的指令及功能
SQL语法中的指令可分为数据查询语言(DQL)、数据操作语言(DML)、数据定义语言(DDL)、数据控制语言(DCL)和事务控制语言(TCL),以下是详细分类总结:
一、数据查询语言(DQL)
- SELECT
功能:从数据库中检索数据,支持条件过滤、排序、聚合、联接和子查询。
示例:
SELECT name, age FROM employees WHERE department = 'IT';
子查询
- 功能:在查询中嵌套其他查询,实现复杂逻辑。
- 示例:
SELECT name FROM employees WHERE salary > (SELECT AVG(salary) FROM employees);
二、数据操作语言(DML)
INSERT
- 功能:向表中插入单行或多行数据,支持从其他表插入数据。
- 示例:
INSERT INTO employees (name, age, department) VALUES ('Alice', 30, 'HR');
UPDATE
- 功能:修改表中的现有数据,支持条件更新。
- 示例:
UPDATE employees SET age = 31 WHERE name = 'Alice';
DELETE
- 功能:从表中删除数据,支持条件删除。
- 示例:
DELETE FROM employees WHERE department = 'Sales';
三、数据定义语言(DDL)
CREATE
- 功能:创建数据库对象(如表、索引、视图等)。
- 示例:
CREATE TABLE employees (id INT PRIMARY KEY, name VARCHAR(100), age INT);
ALTER
- 功能:修改表结构(如添加、删除或修改列,添加或删除索引)。
- 示例:
ALTER TABLE employees ADD COLUMN email VARCHAR(255);
DROP
- 功能:删除数据库对象(如表、索引、视图等),操作不可逆。
- 示例:
DROP TABLE employees;
TRUNCATE
- 功能:快速删除表中的所有数据,保留表结构,不可回滚。
- 示例:
TRUNCATE TABLE employees;
四、数据控制语言(DCL)
GRANT
- 功能:授予用户对数据库对象的权限(如SELECT、INSERT、UPDATE等)。
- 示例:
GRANT SELECT ON employees TO user1;
REVOKE
- 功能:撤销之前授予的权限。
- 示例:
REVOKE SELECT ON employees FROM user1;
五、事务控制语言(TCL)
COMMIT
- 功能:提交事务,使更改永久生效。
- 示例:
COMMIT;
ROLLBACK
- 功能:回滚事务,撤销未提交的更改。
- 示例:
ROLLBACK;
BEGIN TRANSACTION
- 功能:开始一个新事务。
- 示例:
BEGIN TRANSACTION;
六、其他常用指令
JOIN
- 功能:联接多个表,实现数据关联查询(如INNER JOIN、LEFT JOIN等)。
- 示例:
SELECT e.name, d.department_name FROM employees e INNER JOIN departments d ON e.department_id = d.id;
GROUP BY
- 功能:对结果集进行分组,通常与聚合函数(如COUNT、SUM、AVG)一起使用。
- 示例:
SELECT department_id, COUNT(*) as employee_count FROM employees GROUP BY department_id;
HAVING
- 功能:对分组后的结果进行过滤。
- 示例:
SELECT department_id, COUNT(*) as employee_count FROM employees GROUP BY department_id HAVING COUNT(*) > 5;
ORDER BY
- 功能:对结果集进行排序(升序ASC或降序DESC)。
- 示例:
SELECT name, age FROM employees ORDER BY age DESC;
DISTINCT
- 功能:返回唯一不同的值,去除重复数据。
- 示例:
SELECT DISTINCT department FROM employees;
LIKE
- 功能:在WHERE子句中搜索列中的指定模式(支持通配符%)。
- 示例:
SELECT name FROM employees WHERE name LIKE 'A%';
INDEX
- 功能:创建或删除索引以加速查询。
- 示例:
CREATE INDEX idx_name ON employees(name);
VIEW
- 功能:创建或删除视图,视图是基于SQL语句的结果集的虚拟表。
- 示例:
CREATE VIEW hr_employees AS SELECT name, age FROM employees WHERE department = 'HR';
示例代码
创建表格
CREATE DATABASE `sql_tutorial`;
USE `sql_tutorial`;CREATE TABLE `student` (`student_id` INT PRIMARY KEY, -- 修正拼写`name` VARCHAR(20),`major` VARCHAR(20)
);-- 添加字段
ALTER TABLE `student` ADD gpa DECIMAL(3,2);-- 删除字段
ALTER TABLE `student` DROP COLUMN gpa;-- 查看表结构
DESCRIBE `student`;-- 删除表(最后执行)
DROP TABLE `student`;
存储资料
-- 创建 student 表
CREATE TABLE `student` (`student_id` INT, -- 学生ID,整数类型`name` VARCHAR(20), -- 学生姓名,可变长度字符串(最多20字符)`major` VARCHAR(20), -- 专业名称,可变长度字符串(最多20字符)PRIMARY KEY(`student_id`) -- 设置 student_id 为主键
);-- 查询 student 表中的所有数据
SELECT * FROM `student`;-- 向 student 表中插入一条完整记录
INSERT INTO `student` VALUES(3, '小蓝', '英语');-- 向 student 表中插入部分字段(major 和 student_id),需指定列名
INSERT INTO `student` (`major`, `student_id`) VALUES('英语', 5);
限制约束
-- 注释:constraints 表示约束
-- 创建 student 表
CREATE TABLE `student` (`student_id` INT AUTO_INCREMENT, -- 学生ID,整数类型,自动递增`name` VARCHAR(20), -- 学生姓名,可变长度字符串(最多20字符)`major` VARCHAR(20), -- 专业名称,可变长度字符串(最多20字符)PRIMARY KEY(`student_id`) -- 主键约束:student_id 为主键
);-- 删除 student 表(如果已存在)
DROP TABLE `student`;-- 查询 student 表中的所有数据
SELECT * FROM `student`;-- 插入完整记录(指定所有字段的值)
INSERT INTO `student` VALUES(1, '小白', '英语');-- 插入完整记录(另一种写法,显式指定字段名)
INSERT INTO `student` (`name`, `major`) VALUES('小绿', '英语'); -- 注意:此处未指定 student_id,依赖 AUTO_INCREMENT
在SQL中,除了 AUTO_INCREMENT
(或某些数据库中的 SERIAL
、IDENTITY
等自动递增约束)之外,还有多种常见的限制(约束)语句用于定义表的结构和数据完整性。以下是主要的约束类型及其说明:
主键约束(PRIMARY KEY)
- 功能:唯一标识表中的每一行记录,不允许重复值和
NULL
。
外键约束(FOREIGN KEY)
- 功能:确保一个表中的字段值引用另一个表的主键或唯一键,维护表间关系。
唯一约束(UNIQUE)
- 功能:确保字段或字段组合的值唯一,但允许
NULL
(除非显式设置为NOT NULL
)。
非空约束(NOT NULL)
- 功能:强制字段必须包含值,不能为
NULL
。
检查约束(CHECK)
- 功能:限制字段值的范围或格式(部分数据库支持,如 PostgreSQL、SQL Server、MySQL 8.0+)。
修改删除资料
-- 关闭安全更新模式(仅测试环境使用)
SET SQL_SAFE_UPDATES = 0;-- 创建 student 表
CREATE TABLE `student` (`student_id` INT PRIMARY KEY,`name` VARCHAR(20),`major` VARCHAR(20),`score` INT
);-- 插入测试数据
INSERT INTO `student` VALUES (1, '小白', '数学', 90);
INSERT INTO `student` VALUES (2, '小蓝', '英语', 85);-- 查询初始数据
SELECT * FROM `student`;-- 更新数据:修改 student_id = 1 的记录
UPDATE `student`
SET `name` = '小灰', `major` = '物理', `score` = 95 -- 同时修改多个字段
WHERE `student_id` = 1;-- 删除数据:删除 student_id = 2 的记录
DELETE FROM `student`
WHERE `student_id` = 2;-- 查询更新后的数据
SELECT * FROM `student`;-- 删除表(清理测试数据)
DROP TABLE `student`;
取得资料
-- 创建 student 表(示例用)
CREATE TABLE `student` (`student_id` INT PRIMARY KEY, -- 学生ID,主键`name` VARCHAR(20), -- 学生姓名`major` VARCHAR(20), -- 专业`score` INT, -- 分数`enroll_date` DATE -- 入学日期(用于后续示例)
);-- 插入测试数据
INSERT INTO `student` VALUES (1, '小白', '数学', 85, '2023-09-01');
INSERT INTO `student` VALUES (2, '小蓝', '英语', 92, '2023-09-02');
INSERT INTO `student` VALUES (3, '小绿', '物理', 78, '2023-09-03');
INSERT INTO `student` VALUES (4, '小灰', '英语', 88, '2023-09-04');
INSERT INTO `student` VALUES (5, '小紫', '数学', 95, '2023-09-05');-- ==================================
-- 1. 选择特定字段
-- ==================================
SELECT `student_id`, `name`, `major`
FROM `student`;-- ==================================
-- 2. 带条件的查询(WHERE)
-- ==================================
-- 查询分数大于 80 且专业为 '英语' 的学生
SELECT *
FROM `student`
WHERE `score` > 80 AND `major` = '英语';-- 查询专业为 '数学' 或 '物理' 的学生
SELECT *
FROM `student`
WHERE `major` IN ('数学', '物理'); -- 使用 IN 替代 OR-- ==================================
-- 3. 排序结果(ORDER BY)
-- ==================================
-- 按分数降序排列,如果分数相同则按姓名升序排列
SELECT *
FROM `student`
ORDER BY `score` DESC, `name` ASC;-- ==================================
-- 5. 限制返回行数(LIMIT)
-- ==================================
-- 只返回分数最高的前 3 名学生
SELECT *
FROM `student`
ORDER BY `score` DESC
LIMIT 3;-- ==================================
-- 7. 计算字段(AS 别名)
-- ==================================
-- 计算学生的分数等级(假设 90+ 为 A,80-89 为 B,依此类推)
SELECT `name`,`score`,CASE WHEN `score` >= 90 THEN 'A'WHEN `score` >= 80 THEN 'B'WHEN `score` >= 70 THEN 'C'ELSE 'D'END AS grade
FROM `student`;
聚合函数
-- 4. 分组统计(GROUP BY 和聚合函数)
-- ==================================
-- 统计每个专业的平均分和最高分
SELECT `major`,AVG(`score`) AS avg_score, -- 平均分MAX(`score`) AS max_score -- 最高分
FROM `student`
GROUP BY `major`;-- 统计学生人数大于 1 的专业
SELECT `major`,COUNT(*) AS student_count
FROM `student`
GROUP BY `major`
HAVING COUNT(*) > 1; -- HAVING 用于过滤分组后的结果
万用字元模糊查询
-- 模糊查询(LIKE)
-- ==================================
-- 查询姓名中包含 '小' 的学生
SELECT *
FROM `student`
WHERE `name` LIKE '%小%'; -- % 表示任意字符;_代表一个字符
UNION
-- 创建两个示例表
CREATE TABLE `students_2023` (`student_id` INT PRIMARY KEY,`name` VARCHAR(20),`major` VARCHAR(20)
);CREATE TABLE `students_2024` (`student_id` INT PRIMARY KEY,`name` VARCHAR(20),`major` VARCHAR(20)
);-- 插入测试数据
INSERT INTO `students_2023` VALUES
(1, '小白', '数学'),
(2, '小蓝', '英语'),
(3, '小绿', '物理');INSERT INTO `students_2024` VALUES
(2, '小蓝', '英语'), -- 与 2023 年重复的学生
(4, '小灰', '化学'),
(5, '小紫', '数学');-- ==================================
-- 1. 使用 UNION 合并两个表的数据(自动去重)
-- ==================================
SELECT `student_id`, `name`, `major` FROM `students_2023`
UNION
SELECT `student_id`, `name`, `major` FROM `students_2024`;
-- 结果:合并后的数据,重复行(如 student_id = 2 的小蓝)会被去除。-- ==================================
-- 2. 使用 UNION ALL 合并数据(保留重复行)
-- ==================================
SELECT `student_id`, `name`, `major` FROM `students_2023`
UNION ALL
SELECT `student_id`, `name`, `major` FROM `students_2024`;
-- 结果:保留所有行,包括重复行。-- ==================================
-- 3. 结合 ORDER BY 对最终结果排序
-- ==================================
SELECT `student_id`, `name`, `major` FROM `students_2023`
UNION
SELECT `student_id`, `name`, `major` FROM `students_2024`
ORDER BY `name`; -- 按姓名升序排列-- ==================================
-- 4. 实际应用场景:合并不同条件筛选的数据
-- ==================================
-- 合并 2023 年数学专业学生和 2024 年英语专业学生
SELECT `student_id`, `name`, `major` FROM `students_2023` WHERE `major` = '数学'
UNION
SELECT `student_id`, `name`, `major` FROM `students_2024` WHERE `major` = '英语';-- ==================================
-- 清理测试数据(可选)
-- ==================================
DROP TABLE `students_2023`;
DROP TABLE `students_2024`;
注意事项
- 列数和数据类型匹配:
- 每个
SELECT
语句的列数必须相同,且对应列的数据类型需兼容。 - 示例:若第一个
SELECT
返回(INT, VARCHAR, DATE)
,后续SELECT
也需返回相同类型的列。
- 每个
- 性能考虑:
UNION
需要去重,可能消耗更多资源。若无需去重,优先使用UNION ALL
。
- 排序:
ORDER BY
只能出现在最后一个SELECT
语句之后,且排序字段需存在于所有SELECT
语句中(或通过列序号指定,如ORDER BY 2
表示按第二列排序)。
- 别名处理:
- 最终结果集的列名以第一个
SELECT
语句的列名为准。
- 最终结果集的列名以第一个
总结
UNION
:合并结果并去重,适用于需要唯一数据的场景。UNION ALL
:合并结果并保留重复行,性能更高。- 典型用途:合并不同表或不同条件的数据,生成统一视图。
JOIN
JOIN
的作用
- 联接多个表:通过关联字段(通常是主键和外键)将多个表的数据合并为一个结果集。
- 常见类型:
INNER JOIN
:仅返回两表中匹配的行。LEFT JOIN
(或LEFT OUTER JOIN
):返回左表的所有行,即使右表无匹配。RIGHT JOIN
(或RIGHT OUTER JOIN
):返回右表的所有行,即使左表无匹配。FULL JOIN
(MySQL 不直接支持,需用UNION
模拟):返回两表的所有行。CROSS JOIN
:返回两表的笛卡尔积(不推荐无条件使用)。
-- 创建示例表
CREATE TABLE `students` (`student_id` INT PRIMARY KEY,`name` VARCHAR(20),`major_id` INT -- 外键,关联到 majors 表
);CREATE TABLE `majors` (`major_id` INT PRIMARY KEY,`major_name` VARCHAR(20)
);-- 插入测试数据
INSERT INTO `students` VALUES
(1, '小白', 101),
(2, '小蓝', 102),
(3, '小绿', 103),
(4, '小灰', NULL); -- 无专业的学生INSERT INTO `majors` VALUES
(101, '数学'),
(102, '英语'),
(104, '物理'); -- 无学生选择的专业-- ==================================
-- 1. INNER JOIN(内连接)
-- ==================================
-- 只返回两表中匹配的行(即 students.major_id = majors.major_id)
SELECT s.`student_id`,s.`name`,m.`major_name`
FROM `students` s
INNER JOIN `majors` m ON s.`major_id` = m.`major_id`;
-- 结果:仅返回有专业的学生及其专业名称。-- ==================================
-- 2. LEFT JOIN(左连接)
-- ==================================
-- 返回左表(students)的所有行,即使右表(majors)无匹配
SELECT s.`student_id`,s.`name`,m.`major_name`
FROM `students` s
LEFT JOIN `majors` m ON s.`major_id` = m.`major_id`;
-- 结果:包含所有学生,无专业的显示为 NULL。-- ==================================
-- 3. RIGHT JOIN(右连接)
-- ==================================
-- 返回右表(majors)的所有行,即使左表(students)无匹配
SELECT s.`student_id`,s.`name`,m.`major_name`
FROM `students` s
RIGHT JOIN `majors` m ON s.`major_id` = m.`major_id`;
-- 结果:包含所有专业,无学生选择的专业显示学生列为 NULL。
子查询
子查询的概念
- 定义:子查询(Subquery)是嵌套在另一个查询(如
SELECT
、INSERT
、UPDATE
、DELETE
)内部的查询语句。 - 作用:
- 动态生成条件或数据。
- 将复杂查询分解为多个步骤。
- 常见位置:
WHERE
或HAVING
子句中作为条件。SELECT
列表中作为字段。FROM
子句中作为临时表(派生表)。
- 执行顺序:子查询通常先于外层查询执行。
--子查询
-- ==================================
-- 查询分数高于平均分的学生
SELECT *
FROM `student`
WHERE `score` > (SELECT AVG(`score`) FROM `student`);