MySQL 基础语法完全指南

小飞兽 数据库 508 次阅读 2026-06-02

概述

MySQL 是最流行的开源关系型数据库之一,SQL(Structured Query Language)是操作 MySQL 的标准语言。无论是简单的数据查询还是复杂的多表联结,SQL 都是每个后端开发者必须掌握的核心技能。本文系统介绍 MySQL 的基础语法,覆盖了数据定义(DDL)、数据操作(DML)、查询优化和常见函数,帮助你快速上手并写出高效的 SQL 语句。

基础语法

SQL 语句可以分为几大类:DDL(Data Definition Language)用于定义数据库对象(表、索引、视图),DML(Data Manipulation Language)用于操作数据(增删改查),DCL(Data Control Language)用于权限控制。在实际开发中,SELECT(查询)是使用最频繁的部分,也是最复杂的部分。

    • SELECT:从表中查询数据,是 SQL 最核心的部分。
    • INSERT:向表中插入新记录。
    • UPDATE:修改表中已存在的记录。
    • DELETE:删除表中的记录(注意加 WHERE 条件)。
    • CREATE/ALTER/DROP:DDL 语句,创建或修改表结构。

    理解 SQL 的执行顺序有助于写出正确的子查询。实际执行顺序是:FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY -> LIMIT,而不是按照书写顺序。

    完整代码示例+注释

    -- === 创建数据库和表 ===
    CREATE DATABASE IF NOT EXISTS shop DEFAULT CHARSET utf8mb4;
    USE shop;
    

    -- 用户表
    CREATE TABLE IF NOT EXISTS users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL UNIQUE,
    email VARCHAR(100) NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_email (email)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

    -- 订单表
    CREATE TABLE IF NOT EXISTS orders (
    id INT PRIMARY KEY AUTO_INCREMENT,
    user_id INT NOT NULL,
    total_amount DECIMAL(10,2) NOT NULL DEFAULT 0,
    status ENUM('pending','paid','shipped','completed','cancelled') DEFAULT 'pending',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (user_id) REFERENCES users(id)
    );

    -- === 插入数据 ===
    INSERT INTO users (username, email) VALUES
    ('张三', 'zhangsan@example.com'),
    ('李四', 'lisi@example.com'),
    ('王五', 'wangwu@example.com');

    INSERT INTO orders (user_id, total_amount, status) VALUES
    (1, 299.00, 'paid'),
    (1, 150.50, 'shipped'),
    (2, 89.00, 'pending'),
    (3, 520.00, 'completed');

    -- === 基础查询 ===
    -- 查询所有用户
    SELECT id, username, email FROM users;

    -- 带 WHERE 条件过滤
    SELECT * FROM orders WHERE status = 'paid' AND total_amount > 100;

    -- 聚合统计
    SELECT
    COUNT(*) as total_orders,
    SUM(total_amount) as total_revenue,
    AVG(total_amount) as avg_order_value,
    MAX(total_amount) as max_order
    FROM orders;

    -- GROUP BY 分组统计
    SELECT
    u.username,
    COUNT(o.id) as order_count,
    SUM(o.total_amount) as total_spent
    FROM users u
    LEFT JOIN orders o ON u.id = o.user_id
    GROUP BY u.id, u.username
    HAVING order_count > 0
    ORDER BY total_spent DESC
    LIMIT 10;

    -- === 子查询:查询消费最高的前3名用户 ===
    SELECT u.username, total_spent
    FROM (
    SELECT user_id, SUM(total_amount) as total_spent
    FROM orders
    WHERE status != 'cancelled'
    GROUP BY user_id
    ) o
    JOIN users u ON o.user_id = u.id
    ORDER BY total_spent DESC
    LIMIT 3;

    -- === 联合查询:同时查询多个状态 ===
    SELECT id, total_amount, '高单价订单' as tag
    FROM orders
    WHERE total_amount > 200
    UNION ALL
    SELECT id, total_amount, '待处理订单' as tag
    FROM orders
    WHERE status = 'pending'
    ORDER BY total_amount DESC;

    -- === 更新和删除(注意 WHERE) ===
    -- 将所有 pending 订单更新为 cancelled(超过30天)
    UPDATE orders
    SET status = 'cancelled', updated_at = NOW()
    WHERE status = 'pending'
    AND created_at < DATE_SUB(NOW(), INTERVAL 30 DAY);

    -- 删除指定用户的所有订单(先删子表再删主表)
    DELETE FROM orders WHERE user_id = 1;
    DELETE FROM users WHERE id = 1;

    运行效果

    执行上述 SQL 后,shop 数据库中会创建 users 和 orders 两张表,并插入测试数据。GROUP BY 查询会输出每个用户的订单数和累计消费金额,按消费降序排列。子查询示例找出消费最高的前3名用户并显示用户名和消费总额。UNION ALL 示例将高单价订单和待处理订单合并展示,并标注来源标签。

    UPDATE 和 DELETE 操作特别强调 WHERE 条件,缺少 WHERE 会导致全表数据被修改或清空。在生产环境中执行 UPDATE/DELETE 前,建议先用 SELECT 确认影响范围,或者在事务中执行并设置合适的隔离级别。

    常见问题

    Q1:为什么查询很慢,怎么优化
    首先检查是否在 WHERE 条件列上建立了索引(用 EXPLAIN 查看执行计划)。避免在索引列上使用函数或运算(如 WHERE YEAR(created_at) = 2024),这会导致索引失效。LIMIT 分页时,使用覆盖索引(covering index)避免回表。对于大表 JOIN,确保关联字段类型一致且都有索引。

    Q2:LEFT JOIN 和 INNER JOIN 的区别
    INNER JOIN 只保留两表都匹配的记录,如果一方的关联字段为 NULL 或找不到匹配则被过滤掉。LEFT JOIN 保留左表全部记录,右表没有匹配的字段填充为 NULL。右表需要用 IS NOT NULL 条件过滤才能达到类似 INNER JOIN 的效果,但语义不同。

    Q3:如何避免 SQL 注入
    永远不要将用户输入直接拼接到 SQL 字符串中。使用预处理语句(Prepared Statement),在 PHP 中用 PDO 或 MySQLi,在 Python 中用 mysql-connector 或 SQLAlchemy ORM。预处理语句将 SQL 结构和数据分离,数据库引擎会自动转义特殊字符。

    Q4:DECIMAL 和 FLOAT/DOUBLE 的区别
    DECIMAL 是精确数值类型,适合存储金额等需要精确计算的数据,运算速度稍慢。FLOAT 和 DOUBLE 是浮点数类型,存储近似值,在涉及大量计算或比较时可能产生精度误差。金融类系统务必使用 DECIMAL(10,2) 等精确类型。

    延伸阅读

    • EXPLAIN 分析:使用 EXPLAIN 查看查询执行计划,是分析 SQL 性能瓶颈的必备工具。
    • MySQL Performance Blog:Percona 团队的博客,提供大量 MySQL 深度调优案例。
  • 《高性能 MySQL》:MySQL 领域的经典书籍,涵盖索引设计、查询优化、复制配置等核心主题。