瑞安市转运信息网

MySQL表的约束与基本查询图文详解

2026-04-05 08:23:02 浏览次数:1
详细信息

MySQL表的约束与基本查询图文详解

一、表的约束详解

1. 约束的作用

约束用于确保数据库中数据的完整性、一致性和准确性,防止无效数据进入数据库。

2. 常用约束类型

(1) PRIMARY KEY(主键约束)
-- 创建表时指定主键
CREATE TABLE students (
    id INT PRIMARY KEY,           -- 方式1:列级约束
    name VARCHAR(50)
);

-- 或
CREATE TABLE students (
    id INT,
    name VARCHAR(50),
    PRIMARY KEY (id)              -- 方式2:表级约束
);

-- 复合主键
CREATE TABLE enrollments (
    student_id INT,
    course_id INT,
    enroll_date DATE,
    PRIMARY KEY (student_id, course_id)
);

特点:

(2) FOREIGN KEY(外键约束)
-- 创建部门表
CREATE TABLE departments (
    dept_id INT PRIMARY KEY,
    dept_name VARCHAR(50)
);

-- 创建员工表,包含外键
CREATE TABLE employees (
    emp_id INT PRIMARY KEY,
    emp_name VARCHAR(50),
    dept_id INT,
    FOREIGN KEY (dept_id) REFERENCES departments(dept_id)
    ON DELETE CASCADE      -- 级联删除
    ON UPDATE CASCADE      -- 级联更新
);

外键约束图示:

┌─────────────────┐       ┌─────────────────┐
│   departments   │       │    employees    │
├─────────────────┤       ├─────────────────┤
│   dept_id (PK)  │◄──────│   dept_id (FK)  │
│   dept_name     │       │   emp_id (PK)   │
│                 │       │   emp_name      │
└─────────────────┘       └─────────────────┘
      主表                        从表

外键操作选项:

(3) UNIQUE(唯一约束)
CREATE TABLE users (
    id INT PRIMARY KEY,
    email VARCHAR(100) UNIQUE,      -- 列级约束
    username VARCHAR(50)
);

-- 或表级约束
CREATE TABLE users (
    id INT PRIMARY KEY,
    email VARCHAR(100),
    username VARCHAR(50),
    UNIQUE (email)                    -- 表级约束
);

特点:

(4) NOT NULL(非空约束)
CREATE TABLE products (
    id INT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    price DECIMAL(10,2) NOT NULL
);
(5) CHECK(检查约束) - MySQL 8.0+支持
CREATE TABLE employees (
    id INT PRIMARY KEY,
    name VARCHAR(50),
    age INT CHECK (age >= 18 AND age <= 65),
    salary DECIMAL(10,2) CHECK (salary > 0)
);
(6) DEFAULT(默认值约束)
CREATE TABLE orders (
    order_id INT PRIMARY KEY,
    order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    status VARCHAR(20) DEFAULT 'pending'
);
(7) AUTO_INCREMENT(自增约束)
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50)
);

-- 设置自增起始值
ALTER TABLE users AUTO_INCREMENT = 1000;

3. 约束管理

-- 添加约束
ALTER TABLE students ADD PRIMARY KEY (id);
ALTER TABLE employees ADD FOREIGN KEY (dept_id) REFERENCES departments(dept_id);
ALTER TABLE users ADD CONSTRAINT uc_email UNIQUE (email);
ALTER TABLE products MODIFY COLUMN name VARCHAR(100) NOT NULL;

-- 删除约束
ALTER TABLE employees DROP FOREIGN KEY fk_dept;  -- 需要知道约束名
ALTER TABLE users DROP INDEX uc_email;           -- 删除唯一约束
ALTER TABLE students DROP PRIMARY KEY;

二、基本查询图文详解

1. SELECT基础查询结构

┌─────────────────────────────────────────────────────┐
│                  SELECT 语句结构                     │
├─────────────────────────────────────────────────────┤
│ SELECT [DISTINCT] 列1, 列2, ...                      │
│ FROM 表名                                            │
│ [WHERE 条件]                                         │
│ [GROUP BY 分组列]                                    │
│ [HAVING 分组条件]                                    │
│ [ORDER BY 排序列 [ASC|DESC]]                        │
│ [LIMIT 数量];                                       │
└─────────────────────────────────────────────────────┘

2. 基本查询示例

示例数据表结构:
-- 创建示例表
CREATE TABLE employees (
    emp_id INT PRIMARY KEY,
    emp_name VARCHAR(50),
    dept_id INT,
    salary DECIMAL(10,2),
    hire_date DATE,
    job_title VARCHAR(50)
);

CREATE TABLE departments (
    dept_id INT PRIMARY KEY,
    dept_name VARCHAR(50)
);

-- 插入示例数据
INSERT INTO departments VALUES 
(1, '技术部'), (2, '销售部'), (3, '人事部');

INSERT INTO employees VALUES 
(1, '张三', 1, 8000, '2020-01-15', '工程师'),
(2, '李四', 1, 9000, '2019-05-20', '高级工程师'),
(3, '王五', 2, 7000, '2021-03-10', '销售代表'),
(4, '赵六', 2, 8500, '2018-11-30', '销售经理'),
(5, '钱七', 3, 6000, '2022-02-28', 'HR专员');

3. 查询类型详解

(1) 简单查询
-- 查询所有列
SELECT * FROM employees;

-- 查询特定列
SELECT emp_id, emp_name, salary FROM employees;

-- 使用别名
SELECT emp_id AS 员工编号, 
       emp_name AS 姓名,
       salary * 12 AS 年薪
FROM employees;

-- 去重查询
SELECT DISTINCT dept_id FROM employees;
(2) WHERE条件查询
-- 比较运算符
SELECT * FROM employees WHERE salary > 8000;
SELECT * FROM employees WHERE hire_date >= '2020-01-01';

-- 逻辑运算符
SELECT * FROM employees 
WHERE salary > 7000 AND dept_id = 1;

SELECT * FROM employees 
WHERE dept_id = 1 OR dept_id = 2;

-- BETWEEN范围查询
SELECT * FROM employees 
WHERE salary BETWEEN 7000 AND 9000;

-- IN查询
SELECT * FROM employees 
WHERE dept_id IN (1, 2);

-- LIKE模糊查询
SELECT * FROM employees 
WHERE emp_name LIKE '张%';    -- 张开头

SELECT * FROM employees 
WHERE emp_name LIKE '%三';    -- 三结尾

SELECT * FROM employees 
WHERE emp_name LIKE '%四%';   -- 包含四

-- IS NULL判断
SELECT * FROM employees WHERE job_title IS NULL;
(3) ORDER BY排序
-- 单列排序
SELECT * FROM employees ORDER BY salary DESC;

-- 多列排序
SELECT * FROM employees 
ORDER BY dept_id ASC, salary DESC;

-- 按表达式排序
SELECT *, salary * 12 AS annual_salary 
FROM employees 
ORDER BY annual_salary DESC;
(4) LIMIT限制
-- 限制行数
SELECT * FROM employees LIMIT 3;

-- 分页查询
SELECT * FROM employees LIMIT 2, 3;  -- 跳过2条,取3条

-- 与ORDER BY结合
SELECT * FROM employees 
ORDER BY salary DESC 
LIMIT 3;  -- 查询工资最高的3人

4. 聚合函数查询

-- 常用聚合函数
SELECT 
    COUNT(*) AS 员工总数,
    AVG(salary) AS 平均工资,
    MAX(salary) AS 最高工资,
    MIN(salary) AS 最低工资,
    SUM(salary) AS 工资总额
FROM employees;

-- COUNT的不同用法
SELECT COUNT(*) FROM employees;           -- 所有行数
SELECT COUNT(emp_id) FROM employees;      -- 非NULL值计数
SELECT COUNT(DISTINCT dept_id) FROM employees;  -- 去重计数

5. GROUP BY分组查询

-- 按部门分组统计
SELECT 
    dept_id,
    COUNT(*) AS 人数,
    AVG(salary) AS 平均工资,
    MAX(salary) AS 最高工资
FROM employees
GROUP BY dept_id;

-- GROUP BY执行流程图示:
┌─────────────────────────────────────────┐
│             GROUP BY 流程                │
├─────────────────────────────────────────┤
│ 1. FROM employees                       │
│ 2. WHERE 筛选数据                        │
│ 3. GROUP BY dept_id 分组                 │
│ 4. 对每组应用聚合函数                     │
│ 5. SELECT 选择显示的列                   │
│ 6. ORDER BY 排序                        │
└─────────────────────────────────────────┘

6. HAVING分组后筛选

-- HAVING vs WHERE
SELECT dept_id, AVG(salary) AS avg_salary
FROM employees
GROUP BY dept_id
HAVING AVG(salary) > 7500;  -- 分组后筛选

-- WHERE和HAVING一起使用
SELECT dept_id, AVG(salary) AS avg_salary
FROM employees
WHERE hire_date >= '2020-01-01'  -- 分组前筛选
GROUP BY dept_id
HAVING AVG(salary) > 7000;       -- 分组后筛选

WHERE vs HAVING区别:

┌───────────────────┬───────────────────┐
│     WHERE         │     HAVING        │
├───────────────────┼───────────────────┤
│ 分组前筛选         │ 分组后筛选         │
│ 作用于原始记录     │ 作用于分组结果     │
│ 不能使用聚合函数   │ 可以使用聚合函数   │
│ 先执行            │ 后执行            │
└───────────────────┴───────────────────┘

7. 多表查询(JOIN)

(1) INNER JOIN(内连接)
-- 显式内连接
SELECT e.emp_name, d.dept_name, e.salary
FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id;

-- 隐式内连接
SELECT e.emp_name, d.dept_name
FROM employees e, departments d
WHERE e.dept_id = d.dept_id;
(2) LEFT JOIN(左连接)
-- 左连接:包含左表所有记录,右表匹配不到则为NULL
SELECT e.emp_name, d.dept_name
FROM employees e
LEFT JOIN departments d ON e.dept_id = d.dept_id;

JOIN类型图示:

内连接 (INNER JOIN)       左连接 (LEFT JOIN)
┌─────────┐             ┌─────────┐
│   A     │             │   A     │
│  A∩B    │             │  A∪(B∩A)│
│   B     │             │    B    │
└─────────┘             └─────────┘
(3) 其他JOIN类型
-- RIGHT JOIN(右连接)
SELECT e.emp_name, d.dept_name
FROM employees e
RIGHT JOIN departments d ON e.dept_id = d.dept_id;

-- FULL OUTER JOIN(MySQL不支持,可用UNION模拟)
SELECT e.emp_name, d.dept_name
FROM employees e LEFT JOIN departments d ON e.dept_id = d.dept_id
UNION
SELECT e.emp_name, d.dept_name
FROM employees e RIGHT JOIN departments d ON e.dept_id = d.dept_id;

8. 子查询

-- 标量子查询(返回单个值)
SELECT emp_name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);

-- 列子查询(返回一列)
SELECT emp_name, dept_id
FROM employees
WHERE dept_id IN (
    SELECT dept_id FROM departments 
    WHERE dept_name LIKE '%技术%'
);

-- 行子查询
SELECT * FROM employees
WHERE (dept_id, salary) = (
    SELECT dept_id, MAX(salary) 
    FROM employees 
    GROUP BY dept_id 
    LIMIT 1
);

-- 表子查询
SELECT dept_id, avg_salary
FROM (
    SELECT dept_id, AVG(salary) AS avg_salary
    FROM employees
    GROUP BY dept_id
) AS dept_stats
WHERE avg_salary > 7000;

9. UNION联合查询

-- UNION合并结果集(去重)
SELECT emp_name, salary FROM employees WHERE dept_id = 1
UNION
SELECT emp_name, salary FROM employees WHERE salary > 8000;

-- UNION ALL合并(不去重)
SELECT emp_name FROM employees WHERE dept_id = 1
UNION ALL
SELECT emp_name FROM employees WHERE dept_id = 2;

三、查询优化建议

索引优化

查询优化

-- 避免使用SELECT *
SELECT id, name FROM users;  -- 好
SELECT * FROM users;          -- 差(除非确实需要所有列)

-- 使用EXPLAIN分析查询
EXPLAIN SELECT * FROM employees WHERE dept_id = 1;

-- 避免在WHERE中使用函数
WHERE YEAR(hire_date) = 2023;        -- 差
WHERE hire_date >= '2023-01-01';     -- 好

分页优化

-- 传统分页(大数据量性能差)
SELECT * FROM big_table LIMIT 10000, 20;

-- 优化分页(使用索引列)
SELECT * FROM big_table 
WHERE id > 10000 
ORDER BY id 
LIMIT 20;

四、总结

约束是数据库完整性的保证,合理使用约束可以避免脏数据 SELECT查询是SQL核心,掌握各种查询技巧是数据库操作的基础 理解查询执行顺序:FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT 多表连接时要明确连接类型和条件 合理使用子查询和聚合函数可以实现复杂的数据分析需求 始终考虑查询性能,特别是处理大数据量时
相关推荐