sql基础

文章目录

  • [1、DDL 定义或修改表结构](#1、DDL 定义或修改表结构)
  • [2、DML 操作表数据](#2、DML 操作表数据)
  • [3、DQL 查询表数据](#3、DQL 查询表数据)
    • 3.1、基本查询
    • 3.2、关联查询
      • [3.2.1、INNER JOIN(内连接) 最常用](#3.2.1、INNER JOIN(内连接) 最常用)
      • [3.2.2、LEFT JOIN(左外连接)](#3.2.2、LEFT JOIN(左外连接))
      • [3.2.3、RIGHT JOIN(右外连接)](#3.2.3、RIGHT JOIN(右外连接))
      • 3.2.4、多表连接
    • 3.3、聚合查询
      • 3.3.1、五大聚合函数
      • [3.3.2、GROUP BY分组](#3.3.2、GROUP BY分组)
      • [3.3.3、WHERE vs HAVING](#3.3.3、WHERE vs HAVING)
      • 3.3.4、常见场景模板
        • 3.3.4.1、分组计数
        • [3.3.4.2、分组统计 + 排序](#3.3.4.2、分组统计 + 排序)
        • [3.3.4.3、分组内做条件统计(CASE WHEN)](#3.3.4.3、分组内做条件统计(CASE WHEN))
        • [3.3.4.4、HAVING + 多种聚合条件](#3.3.4.4、HAVING + 多种聚合条件)
    • 3.4、子查询
      • [3.4.1、WHERE 子句中(最常见)](#3.4.1、WHERE 子句中(最常见))
      • [3.4.2、FROM 子句中(当作临时表)](#3.4.2、FROM 子句中(当作临时表))
      • [3.4.3、SELECT 子句中(标量子查询)](#3.4.3、SELECT 子句中(标量子查询))
      • [3.4.4、EXISTS vs IN](#3.4.4、EXISTS vs IN)
      • [3.4.5、关联子查询 vs 非关联子查询](#3.4.5、关联子查询 vs 非关联子查询)
      • [3.4.6、ANY 和 ALL](#3.4.6、ANY 和 ALL)
      • [3.4.7、子查询 vs JOIN 的选择](#3.4.7、子查询 vs JOIN 的选择)
    • 4、高级方法
  • 5、性能优化
  • 6、AI用法
  • 7、附录

SQL(Structured Query Language,结构化查询语言)是一种用于管理和操作关系型数据库的标准化编程语言。

SQL按功能被划分为四大核心类别:

  • DDL:定义或修改表结构
  • DML:操作表数据
  • DQL:查询表数据
  • DCL:管理数据库权限

1、DDL 定义或修改表结构

  • CREATE‌:用于创建数据库中的表、视图、索引等
  • ALTER‌:用于修改数据库中的表结构,例如添加、删除或修改列。
  • DROP‌:用于删除数据库中的表、视图、索引等。

1.1、CREATE

📖 语法:

sql 复制代码
CREATE TABLE table_name (
    column1 data_type constraint,
    column2 data_type constraint,
    ...
)

📋 示例:

sql 复制代码
CREATE TABLE departments (
    dept_id   INT PRIMARY KEY AUTO_INCREMENT COMMENT '部门ID',
    dept_name VARCHAR(50) NOT NULL COMMENT '部门名称',
    location  VARCHAR(50) COMMENT '地址'
) COMMENT='部门表';

1.2、ALTER

📖 语法:

sql 复制代码
-- 表新增列
ALTER TABLE table_name ADD column_name data_type;

-- 表删除列
ALTER TABLE table_name DROP COLUMN column_name

1.3、DROP

📖 语法:

sql 复制代码
-- 删除数据库表
DROP TABLE table_name

2、DML 操作表数据

  • INSERT‌:用于向表中插入新的数据行。
  • DELETE‌:用于删除表中的数据行。
  • UPDATE‌:用于修改表中的数据。

2.1、INSERT

📖 语法:

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

📋 示例:

sql 复制代码
INSERT INTO departments (dept_name, location) VALUES
('计算机科学系', 'A栋3楼'),
('数学系',       'B栋2楼'),
('英语系',       'C栋1楼'),
('物理系',       'A栋5楼');

2.2、DELETE

📖 语法:

sql 复制代码
DELETE FROM table_name
WHERE condition;

2.3、UPDATE

📖 语法:

sql 复制代码
UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition;

⚠️:更新和删除记录时要格外小心,要注意 WHERE 后的 condition 条件,防止误删!可以先查询后操作。

3、DQL 查询表数据

  • SELECT‌:用于查询数据。

3.1、基本查询

3.1.1、SELECT

📖 语法:

sql 复制代码
SELECT column1, column2, ...
FROM table_name;

3.1.2、DISTINCT去重

📖 语法:

sql 复制代码
SELECT DISTINCT column1, column2, ...
FROM table_name;

3.1.3、别名

  • 列别名
sql 复制代码
SELECT column_name AS alias_name
FROM table_name;

📌 把三个列(first_name、second_name 和 last_name)结合在一起,并创建一个名为 "full_name" 的别名

sql 复制代码
SELECT CONCAT(first_name, ' ', second_name, ' ', last_name) AS full_name
FROM stu;
  • 表别名
sql 复制代码
SELECT s.name, s.gender, s.age, d.dept_name
FROM students s
JOIN departments d ON s.dept_id = d.dept_id;

3.1.4、WHERE过滤

📖 语法:

sql 复制代码
SELECT column1, column2, ...
FROM table_name
WHERE condition;

📌 WHERE 子句中的运算符:

运算符 描述
= 等于
!= 不等于
> 大于
< 小于
>= 大于等于
<= 小于等于
BETWEEN 在某个范围内
LIKE 搜索某种模式
IN 指定针对某个列的多个可能值
3.1.4.1 BETWEEN区间查询

BETWEEN 操作符选取介于两个值之间的数据范围内的值,这些值可以是数值、文本或者日期。

📖 语法:

sql 复制代码
SELECT column1, column2, ...
FROM table_name
WHERE column BETWEEN value1 AND value2;
3.1.4.2 LIKE 通配符
  • %:匹配任意字符(包括零个字符)。
  • _:匹配单个字符。
  • REGEXP:正则表达式

📌 使用 % 通配符找出所有姓 "张" 的学生:

sql 复制代码
SELECT name, gender, age 
FROM students
WHERE name LIKE '张%';

📌 使用 _ 通配符找出所有姓名第二个字符为 "芳" 的学生:

sql 复制代码
SELECT name, gender, age 
FROM students
WHERE name LIKE '_芳%';

📌 选取 name 以 "张"、"王" 或 "林" 开始的所有学生

sql 复制代码
SELECT * FROM students
WHERE name REGEXP '^[张王林]';
3.1.4.3 IN

WHERE 子句中规定多个值

📖 语法:

sql 复制代码
SELECT column1, column2, ...
FROM table_name
WHERE column IN (value1, value2, ...);

3.1.4、AND & OR 逻辑运算符

运算符 描述
AND 两个条件都成立,则输出
OR 两个条件只要有一个成立,则输出

📋 示例:查找性别为"男",年龄为 21 22 的学生

sql 复制代码
SELECT * FROM students
WHERE gender = '男' AND (age = 21 OR age = 22);

3.1.5、ORDER BY 排序

📖 语法:

sql 复制代码
SELECT column1, column2, ...
FROM table_name
ORDER BY column1, column2, ... ASC|DESC;

📋 示例:按性别升序、年龄倒序显示学生信息

sql 复制代码
SELECT * FROM students
ORDER BY gender, age DESC;
  • ASC:升序排序,默认
  • DESC:降序排序

3.2、关联查询

👉 为什么需要关联查询?

现实中的数据是分散存储的,比如:

  • students 表存学生信息(学号、姓名、院系编号)
  • departments 表存院系信息(院系编号、院系名称)

你想查「张三在哪个院系」------就需要把两张表连起来查。

关联查询的核心:用一张表的某列,去匹配另一张表的对应列,把相关信息拼成一行。

连接有 INNER JOIN、LEFT JOIN、RIGHT JOIN、FULL OUTER JOIN、CROSS JOIN、SELF JOIN、NATURAL JOIN 7 种用法。我们主要介绍常见3种

3.2.1、INNER JOIN(内连接) 最常用

取两张表的交集,只保留匹配上的数据

sql 复制代码
SELECT s.name, d.dept_name
FROM students s
INNER JOIN departments d ON s.dept_id = d.dept_id;

✅ 结果:只显示有院系的学生 (dept_id 能匹配上的)

✅ 使用场景:你只关心有关系的数据,比如"查询所有有院系的学生"

3.2.2、LEFT JOIN(左外连接)

保留左表所有行,右表没有匹配的填 NULL

sql 复制代码
SELECT s.name, d.dept_name
FROM students s
LEFT JOIN departments d ON s.dept_id = d.dept_id;

✅ 结果:所有学生都显示,哪怕院系信息缺失

✅ 使用场景:

  • "查所有学生及其院系(没院系也要显示)"
  • "查没有院系的学生" → WHERE d.dept_id IS NULL

3.2.3、RIGHT JOIN(右外连接)

和 LEFT JOIN 相反,保留右表所有行

sql 复制代码
SELECT s.name, d.dept_name
FROM students s
RIGHT JOIN departments d ON s.dept_id = d.dept_id;

✅ 使用场景:和 LEFT JOIN 一样,习惯用 LEFT 就够了。RIGHT 可以换成调换表顺序的 LEFT。

3.2.4、多表连接

📋 查学生选了哪些课、成绩多少、课程是哪个系开的

sql 复制代码
SELECT s.name, c.course_name, e.grade, d.dept_name
FROM students s
JOIN enrollments e  ON s.stu_id   = e.stu_id
JOIN courses c      ON e.course_id = c.course_id
JOIN departments d  ON c.dept_id   = d.dept_id
WHERE s.name = '张三';

连接顺序不重要,MySQL 优化器会帮你排。 你只需要看清业务链条:

学生 → 选了哪些课 → 这些课的信息 → 这些课属于哪个系

📌 JOIN 后 WHERE 条件放哪里?

规则WHERE 过滤的是最终结果,ON 决定连接方式。

3.3、聚合查询

👉 为什么需要聚合查询?

关联查询是把多行横向拼接 ,解决"数据分散"的问题。聚合查询是把多行纵向压缩成一行统计结果,解决"归类汇总"的问题。绝大多数复杂的SQL,都是先用JOIN"拼宽",获取更多信息;再用GROUP BY"压扁",汇总统计。

聚合的核心:通过分组,把多行变一行,同时用聚合函数做统计。

3.3.1、五大聚合函数

函数 作用 示例
COUNT(x) 计数 COUNT(*) 总行数,COUNT(DISTINCT stu_id) 去重人数
SUM(x) 求和 SUM(grade) 总成绩
AVG(x) 求平均 AVG(grade) 平均分
MAX(x) 最大值 MAX(grade) 最高分
MIN(x) 最小值 MIN(grade) 最低分

NULL 规则

  • COUNT(*) 会计入 NULL 行
  • COUNT(列名) 计入 NULL
  • SUM/AVG/MAX/MIN 忽略 NULL

3.3.2、GROUP BY分组

📖 语法:

sql 复制代码
SELECT   分组列, 聚合函数(统计列)
FROM     表名
[WHERE   过滤条件]        -- ★ 分组前过滤
GROUP BY 分组列
[HAVING  分组后过滤条件]  -- ★ 分组后过滤
[ORDER BY 排序];

📋 示例:按学生分组统计

sql 复制代码
SELECT s.name,
       COUNT(e.course_id) AS 选课数,
       ROUND(AVG(e.grade), 1) AS 平均分,
       MAX(e.grade) AS 最高分
FROM students s
JOIN enrollments e ON s.stu_id = e.stu_id
GROUP BY s.stu_id, s.name;

⚠️ SELECT只能出现

  • GROUP BY 后面的列(分组列)
  • 聚合函数(如 AVGCOUNT

如果放其他列,会报错。

3.3.3、WHERE vs HAVING

这是初学者最困惑的地方。

sql 复制代码
-- ❌ 错的:WHERE 不能放聚合函数
SELECT s.name, AVG(e.grade)
FROM students s JOIN enrollments e ON s.stu_id = e.stu_id
WHERE AVG(e.grade) > 80           -- WHERE 执行时还没分组!
GROUP BY s.stu_id;

-- ✅ 对的:用 HAVING
SELECT s.name, ROUND(AVG(e.grade), 1) AS avg_score
FROM students s JOIN enrollments e ON s.stu_id = e.stu_id
GROUP BY s.stu_id, s.name
HAVING avg_score > 80;
WHERE HAVING
什么时候执行 分组前(过滤原始行) 分组后(过滤分组结果)
能不能用聚合函数 ❌ 不行 ✅ 可以
能不能用别名 ❌ 不行 ✅ 可以

口诀 :先 WHERE 删行,再 GROUP BY 分组,最后 HAVING 删组。

✨ 典型组合:

sql 复制代码
-- 查 2024 学年选课的学生中,平均分 >= 80 的
SELECT s.name, ROUND(AVG(e.grade), 1) AS avg_score
FROM students s
JOIN enrollments e ON s.stu_id = e.stu_id
WHERE e.semester = '2024-2025-1'    -- ① 先过滤出这个学期的选课
GROUP BY s.stu_id, s.name           -- ② 按学生分组
HAVING avg_score >= 80              -- ③ 只保留平均分 >= 80 的
ORDER BY avg_score DESC;            -- ④ 按平均分降序

3.3.4、常见场景模板

3.3.4.1、分组计数
sql 复制代码
-- 每个院系多少人
SELECT d.dept_name, COUNT(s.stu_id) AS cnt
FROM departments d
LEFT JOIN students s ON d.dept_id = s.dept_id 
GROUP BY d.dept_id, d.dept_name;
3.3.4.2、分组统计 + 排序
sql 复制代码
-- 每门课的平均分,从高到低
SELECT c.course_name, ROUND(AVG(e.grade), 1) AS avg_score
FROM courses c
JOIN enrollments e ON c.course_id = e.course_id
GROUP BY c.course_id, c.course_name
ORDER BY avg_score DESC;
3.3.4.3、分组内做条件统计(CASE WHEN)
sql 复制代码
-- 每门课的及格率
SELECT c.course_name,
       COUNT(*) AS 总人数,
       SUM(CASE WHEN e.grade >= 60 THEN 1 ELSE 0 END) AS 及格人数,
       ROUND(SUM(CASE WHEN e.grade >= 60 THEN 1 ELSE 0 END) / COUNT(*) * 100, 1) AS 及格率
FROM courses c
JOIN enrollments e ON c.course_id = e.course_id
GROUP BY c.course_id, c.course_name;
3.3.4.4、HAVING + 多种聚合条件
sql 复制代码
-- 找出选课 >= 2 门且平均分 >= 80 的学生
SELECT s.name, COUNT(*) AS cnt, ROUND(AVG(e.grade), 1) AS avg_score
FROM students s
JOIN enrollments e ON s.stu_id = e.stu_id
GROUP BY s.stu_id, s.name
HAVING cnt >= 2 AND avg_score >= 80;

3.4、子查询

👉 什么是子查询?

子查询就是嵌套在另一个 SQL 里面的查询

3.4.1、WHERE 子句中(最常见)

sql 复制代码
SELECT name, age FROM students
WHERE age > (SELECT AVG(age) FROM students);

子查询先算出平均年龄,主查询用它来比较。

3.4.2、FROM 子句中(当作临时表)

sql 复制代码
SELECT dept_name, avg_score
FROM (
    SELECT d.dept_name, ROUND(AVG(e.grade), 1) AS avg_score
    FROM departments d
    JOIN students s ON d.dept_id = s.dept_id
    JOIN enrollments e ON s.stu_id = e.stu_id
    GROUP BY d.dept_id, d.dept_name
) AS t
WHERE avg_score > 80;

子查询的结果当作一张临时表,外面再查它。

3.4.3、SELECT 子句中(标量子查询)

sql 复制代码
SELECT s.name,
       (SELECT AVG(e2.grade)
        FROM enrollments e2
        WHERE e2.stu_id = s.stu_id) AS personal_avg
FROM students s;

每一行主查询结果,都跑一次子查询,返回单个值

3.4.4、EXISTS vs IN

📋 示例:查询选过课的学生

sql 复制代码
SELECT s.*
FROM students s
WHERE EXISTS (
    SELECT 1 FROM enrollments e WHERE e.stu_id = s.stu_id
);
sql 复制代码
SELECT s.* 
FROM students s 
WHERE s.stu_id in (SELECT s.stu_id from enrollments e WHERE e.stu_id = s.stu_id);
EXISTS IN
子查询返回 只要有行就为 TRUE 具体值列表
性能(子查询结果大时) ✅ 通常更快(半连接优化) 可能较慢
遇到 NULL ✅ 安全 ⚠️ NOT IN 有陷阱
关联子查询 ✅ 支持 ❌ 无法关联

口诀:数据量大用 EXISTS,数据量小或者不是关联子查询用 IN。

3.4.5、关联子查询 vs 非关联子查询

  • 非关联子查询(先跑子查询,再跑主查询)
sql 复制代码
-- 子查询独立运行,不依赖外部
SELECT * FROM students
WHERE age > (SELECT AVG(age) FROM students);  -- 这行独立就能跑
  • 关联子查询(每跑一行主查询,子查询都重新跑一次)
sql 复制代码
SELECT s.name, s.age
FROM students s
WHERE s.age > (
    SELECT AVG(s2.age)
    FROM students s2
    WHERE s2.dept_id = s.dept_id  -- 引用外面的 s.dept_id
);

含义:找比自己院系平均年龄大的学生

📊 执行过程(理解就可以,实际 MySQL 会优化):

复制代码
① 先看张三(计算机系)→ 计算机系平均年龄 (21+20+24)/3 = 21.7 → 张三 21 > 21.7? 否
② 再看李四(计算机系)→ 同上 → 李四 20 > 21.7? 否
③ 看王五(数学系)→ 数学系平均年龄 (22+21+19)/3 = 20.7 → 王五 22 > 20.7? 是 → 返回
...

3.4.6、ANY 和 ALL

用于子查询返回多行时做比较:

  • ANY: 大于子查询中的任意一个(即大于最小值)
sql 复制代码
SELECT * FROM students
WHERE age > ANY (SELECT age FROM students WHERE dept_id = 1);
-- 等价于:age > (SELECT MIN(age) FROM students WHERE dept_id = 1)
  • ALL: 大于子查询中的所有(即大于最大值)
sql 复制代码
SELECT * FROM students
WHERE age > ALL (SELECT age FROM students WHERE dept_id = 1);
-- 等价于:age > (SELECT MAX(age) FROM students WHERE dept_id = 1)

使用场景 :当子查询结果不确定有几行,但你不想用 MAX/MIN 显式写的时候。

3.4.7、子查询 vs JOIN 的选择

很多需求既可以用子查询也可以用 JOIN:

sql 复制代码
-- 方法 1:子查询
SELECT * FROM students
WHERE stu_id IN (SELECT stu_id FROM enrollments);

-- 方法 2:JOIN(需加 DISTINCT)
SELECT DISTINCT s.*
FROM students s
JOIN enrollments e ON s.stu_id = e.stu_id;

选择原则

场景 推荐
只要主表数据,不需要从表的列 子查询(更清晰)
需要从表的列一起展示 JOIN
复杂的分组统计后再过滤 FROM 子查询
检查是否存在(有/没有) EXISTS(性能好)

4、高级方法

  • UCASE() - 将某个字段转换为大写
  • LCASE() - 将某个字段转换为小写
  • MID() - 从某个文本字段提取字符,MySql 中使用
  • SubString(字段,1,end) - 从某个文本字段提取字符
  • LEN() - 返回某个文本字段的长度
  • ROUND() - 对某个数值字段进行指定小数位数的四舍五入
  • NOW() - 返回当前的系统日期和时间
  • FORMAT() - 格式化某个字段的显示方式

5、性能优化

5.1、索引

参见另一篇 📖 Mysql索引基础

5.2、explain慢查询优化

参见另一篇 📖 Mysql联合索引及最左原则

6、AI用法

随着AI发展,其实很多需求只要会描述,几乎不需要手写SQL,所以我们还是要对SQL基础有所了解,结合AI工具,快速生成SQL。或者将SQL语句给AI,让AI让我们分析并且根据自己的需求生成新的SQL语句。

👉 首先,我们先从完整的 SELECT 查询语法结构入手(方括号 \[\] 表示可选):

sql 复制代码
SELECT [DISTINCT] 列名1, 列名2, ...       -- 1、要查哪些列
FROM 表名1                               -- 2、从哪张表/哪几张表
[JOIN 表名2 ON 连接条件]                  -- 3、关联其他表
[WHERE]                                 -- 4、过滤条件
[GROUP BY]                              -- 5、分组
[HAVING]                                -- 6、过滤分组结果
[ORDER BY]                              -- 7、排序
[LIMIT];                                -- 8、限制返回行数

📋 完整的 SELECT 查询:

sql 复制代码
SELECT                                 -- 1、输出列(可配合聚合函数、别名)
    s.nameAS 学生名字,
    COUNT(e.course_id) AS 选课数,
    ROUND(AVG(e.grade), 1) AS 平均分
FROM                                   -- 2、数据来源
    students s
JOIN enrollments e ON s.stu_id = e.stu_id  -- 3、关联其他表
WHERE                                  -- 4、分组前过滤原始数据
    e.semester = '2024-2025-1'
    AND s.age >= 20
GROUP BY                               -- 5、按什么分组
    s.stu_id, s.name
HAVING                                 -- 6、分组后过滤
    平均分 >= 80
ORDER BY                               -- 7、排序
    平均分 DESC
LIMIT 10;                              -- 8、只取前 10 条

⚙️ 执行步骤:

bash 复制代码
1. FROM        → 确定数据来源
2. JOIN        → 连接表
3. WHERE       → 行级过滤条件
4. GROUP BY    → 分组
5. HAVING      → 分组后过滤
6. SELECT      → 选择列 / 计算表达式
7. DISTINCT    → 去重
8. ORDER BY    → 排序
9. LIMIT       → 限制行数

所以,我们描述需求就按照执行步骤,查哪些表,关联哪些表,行级过滤条件是什么,用哪个字段分组,分组过滤条件是什么,最终需要输出哪些列,是否需要去重,是否需要排序,是否需要限制输出行数。

如果需要分析现有的SQL语句,也可以让AI按照上述描述分析输出结果。

后续实战还需要业务运行部蒋老师👩‍🏫提供实际SQL,一起分析。

7、附录

上述介绍的建表语句及表数据

sql 复制代码
-- ============================================================
-- 建表 & 示例数据
-- 场景:学校管理系统(学生、部门、课程、选课)
-- ============================================================

DROP DATABASE IF EXISTS school_db;
CREATE DATABASE school_db CHARACTER SET utf8mb4;
USE school_db;

-- 1. 部门表
CREATE TABLE departments (
    dept_id   INT PRIMARY KEY AUTO_INCREMENT COMMENT '部门ID',
    dept_name VARCHAR(50) NOT NULL COMMENT '部门名称',
    location  VARCHAR(50) COMMENT '地址'
) COMMENT='部门表';

INSERT INTO departments (dept_name, location) VALUES
('计算机科学系', 'A栋3楼'),
('数学系',       'B栋2楼'),
('英语系',       'C栋1楼'),
('物理系',       'A栋5楼');

-- 2. 学生表
CREATE TABLE students (
    stu_id    INT PRIMARY KEY AUTO_INCREMENT COMMENT '学生ID',
    name      VARCHAR(30) NOT NULL COMMENT '姓名',
    gender    CHAR(1) COMMENT '性别',
    age       INT COMMENT '年龄',
    dept_id   INT COMMENT '部门ID',
    enroll_year YEAR COMMENT '部门ID'
) COMMENT='学生表';

INSERT INTO students (name, gender, age, dept_id, enroll_year) VALUES
('张三',   '男', 21, 1, 2022),
('李四',   '女', 20, 1, 2023),
('王五',   '男', 22, 2, 2021),
('赵六',   '女', 21, 2, 2022),
('孙七',   '男', 23, 3, 2021),
('周八',   '女', 20, 3, 2023),
('吴九',   '男', 22, 4, 2022),
('郑十',   '女', 21, 4, 2022),
('陈晓',   '男', 24, 1, 2020),
('林芳',   '女', 19, 2, 2024);

-- 3. 课程表
CREATE TABLE courses (
    course_id   INT PRIMARY KEY AUTO_INCREMENT COMMENT '课程ID',
    course_name VARCHAR(50) NOT NULL COMMENT '课程名称',
    credit      DECIMAL(2,1) COMMENT '学分',
    dept_id     INT COMMENT '部门ID'
) COMMENT='课程表';

INSERT INTO courses (course_name, credit, dept_id) VALUES
('数据结构',       3.0, 1),
('数据库原理',     3.5, 1),
('操作系统',       3.0, 1),
('高等数学',       4.0, 2),
('线性代数',       3.0, 2),
('大学英语',       2.5, 3),
('英语写作',       2.0, 3),
('大学物理',       3.5, 4);

-- 4. 成绩表
CREATE TABLE enrollments (
    stu_id    INT COMMENT '学生ID',
    course_id INT COMMENT '课程ID',
    grade     DECIMAL(5,1) COMMENT '分数',
    semester  VARCHAR(20) COMMENT '学期',
    PRIMARY KEY (stu_id, course_id, semester)
) COMMENT='成绩表';

INSERT INTO enrollments (stu_id, course_id, grade, semester) VALUES
-- 张三
(1, 1, 85.0, '2024-2025-1'),
(1, 2, 92.0, '2024-2025-1'),
(1, 4, 78.0, '2024-2025-1'),
-- 李四
(2, 1, 90.0, '2024-2025-1'),
(2, 3, 74.0, '2024-2025-1'),
(2, 6, 88.0, '2024-2025-1'),
-- 王五
(3, 4, 95.0, '2024-2025-1'),
(3, 5, 88.5, '2024-2025-1'),
-- 赵六
(4, 4, 82.0, '2024-2025-1'),
(4, 5, 91.0, '2024-2025-1'),
(4, 2, 76.0, '2024-2025-1'),
-- 孙七
(5, 6, 60.0, '2024-2025-1'),
(5, 7, 55.0, '2024-2025-1'),
-- 周八
(6, 6, 93.0, '2024-2025-1'),
(6, 7, 87.0, '2024-2025-1'),
-- 吴九
(7, 8, 70.0, '2024-2025-1'),
-- 郑十
(8, 8, 84.0, '2024-2025-1'),
(8, 4, 79.0, '2024-2025-1'),
-- 陈晓
(9, 1, 66.0, '2024-2025-1'),
(9, 2, 73.0, '2024-2025-1'),
(9, 3, 58.0, '2024-2025-1');
相关推荐
三8444 小时前
MySQL 文件读写函数详解:从 CTF 实战到 LOAD_FILE、INTO OUTFILE、LOAD DATA INFILE 应用
数据库·sql
Csvn5 小时前
📊 SQL 入门 Day 21:表设计与约束
后端·sql
Elastic 中国社区官方博客7 小时前
跳过 mapping 爆炸:ES|QL 无需动态 mapping 即可查询无 schema JSON key
大数据·人工智能·sql·elasticsearch·搜索引擎·json·全文检索
for_ever_love__8 小时前
SQL学习: SQL入门与DDL
数据库·sql·学习
Suhan421 天前
SQLAlchemy的两种查询query()查询、stmt=select()查询
数据库·python·sql·oracle
瀚高PG实验室1 天前
SQL优化案例:使用分区表优化SQL查询性能
linux·服务器·数据库·sql·microsoft·postgresql
今天AI了吗1 天前
从聊天到委派:AI Agent 如何推进长期任务
数据库·人工智能·python·sql·rust
名字还没想好☜1 天前
Go 的 database/sql 连接池实战:SetMaxOpenConns 怎么配、连接泄漏怎么查
数据库·sql·golang·go·数据库连接池