Skip to content

MySQL 基础语法 ​

SQL 语言概述 ​

SQL(Structured Query Language,结构化查询语言)是用于管理关系型数据库的标准语言。MySQL 实现了 SQL 标准的大部分功能,并在此基础上增加了一些扩展特性。

SQL 语言的特点 ​

  1. 声明式语言:你只需要描述想要什么结果,而不需要指定如何获得结果

    sql
    -- 声明式:告诉数据库你要什么
    SELECT name, age FROM users WHERE age > 18;
    
    -- 而不是过程式:告诉数据库怎么做
    -- 打开用户表
    -- 逐行检查年龄
    -- 如果年龄大于18,则返回姓名和年龄
  2. 标准化:遵循国际标准,具有良好的可移植性

    sql
    -- 这个查询在大多数数据库系统中都能运行
    SELECT COUNT(*) FROM products WHERE price > 100;
  3. 简洁性:语法相对简单,易于学习和使用

    sql
    -- 简单的查询语句就能完成复杂的数据检索
    SELECT u.name, COUNT(o.id) as order_count
    FROM users u
    LEFT JOIN orders o ON u.id = o.user_id
    GROUP BY u.id;
  4. 功能强大:能够处理复杂的数据操作和查询需求

    sql
    -- 复杂的业务逻辑可以通过SQL表达
    SELECT 
        product_name,
        price,
        CASE 
            WHEN price < 100 THEN '低价'
            WHEN price BETWEEN 100 AND 500 THEN '中价'
            ELSE '高价'
        END as price_category,
        ROW_NUMBER() OVER (PARTITION BY category_id ORDER BY price DESC) as rank_in_category
    FROM products;
  5. 集合操作:基于集合理论,能够高效处理大量数据

    sql
    -- 集合运算:并集
    SELECT user_id FROM orders WHERE order_date >= '2023-01-01'
    UNION
    SELECT user_id FROM reviews WHERE review_date >= '2023-01-01';
    
    -- 集合运算:交集(MySQL 8.0+)
    SELECT user_id FROM orders WHERE order_date >= '2023-01-01'
    INTERSECT
    SELECT user_id FROM reviews WHERE review_date >= '2023-01-01';

SQL 语言分类 ​

SQL 语言按功能可以分为五大类:

1. 数据定义语言(DDL - Data Definition Language) ​

DDL 用于定义和管理数据库结构,包括数据库、表、索引、视图等对象的创建、修改和删除。

主要特点: ​

  • 结构性操作:主要处理数据库对象的结构定义
  • 持久性影响:DDL 操作会永久改变数据库结构
  • 自动提交:大多数 DDL 操作会自动提交事务
  • 权限要求:通常需要较高的数据库权限

核心命令详解: ​

CREATE - 创建数据库对象 ​

创建数据库:

sql
-- 创建数据库
CREATE DATABASE ecommerce 
CHARACTER SET utf8mb4 
COLLATE utf8mb4_unicode_ci;

-- 创建数据库(如果不存在)
CREATE DATABASE IF NOT EXISTS ecommerce;

创建表:

sql
-- 创建用户表
CREATE TABLE users (
    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL UNIQUE,
    email VARCHAR(100) NOT NULL UNIQUE,
    password_hash VARCHAR(255) NOT NULL,
    full_name VARCHAR(100),
    phone VARCHAR(20),
    birth_date DATE,
    gender ENUM('M', 'F', 'Other'),
    status TINYINT DEFAULT 1 COMMENT '1-活跃, 0-禁用',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    
    -- 索引定义
    INDEX idx_email (email),
    INDEX idx_status (status),
    INDEX idx_created_at (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';

-- 创建订单表
CREATE TABLE orders (
    id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    order_no VARCHAR(32) NOT NULL UNIQUE,
    user_id INT UNSIGNED NOT NULL,
    total_amount DECIMAL(10,2) NOT NULL DEFAULT 0.00,
    status ENUM('pending', 'paid', 'shipped', 'completed', 'cancelled') DEFAULT 'pending',
    order_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    
    -- 外键约束
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE RESTRICT ON UPDATE CASCADE,
    
    -- 复合索引
    INDEX idx_user_status (user_id, status),
    INDEX idx_order_date (order_date)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';

创建索引:

sql
-- 创建普通索引
CREATE INDEX idx_username ON users(username);

-- 创建唯一索引
CREATE UNIQUE INDEX uk_email ON users(email);

-- 创建复合索引
CREATE INDEX idx_name_age ON users(full_name, birth_date);

-- 创建前缀索引
CREATE INDEX idx_email_prefix ON users(email(10));

-- 创建全文索引
CREATE FULLTEXT INDEX ft_content ON articles(title, content);

创建视图:

sql
-- 创建用户订单统计视图
CREATE VIEW user_order_stats AS
SELECT 
    u.id,
    u.username,
    u.email,
    COUNT(o.id) as total_orders,
    COALESCE(SUM(o.total_amount), 0) as total_spent,
    MAX(o.order_date) as last_order_date
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.username, u.email;
ALTER - 修改数据库对象结构 ​

修改表结构:

sql
-- 添加列
ALTER TABLE users 
ADD COLUMN avatar_url VARCHAR(500) AFTER email,
ADD COLUMN last_login_at TIMESTAMP NULL;

-- 修改列定义
ALTER TABLE users 
MODIFY COLUMN phone VARCHAR(30),
CHANGE COLUMN full_name real_name VARCHAR(120);

-- 删除列
ALTER TABLE users 
DROP COLUMN avatar_url;

-- 添加索引
ALTER TABLE users 
ADD INDEX idx_phone (phone),
ADD UNIQUE KEY uk_username (username);

-- 删除索引
ALTER TABLE users 
DROP INDEX idx_phone;

-- 添加外键约束
ALTER TABLE orders 
ADD CONSTRAINT fk_user_id 
FOREIGN KEY (user_id) REFERENCES users(id) 
ON DELETE RESTRICT ON UPDATE CASCADE;

-- 删除外键约束
ALTER TABLE orders 
DROP FOREIGN KEY fk_user_id;

修改表选项:

sql
-- 修改表引擎
ALTER TABLE users ENGINE=MyISAM;

-- 修改字符集
ALTER TABLE users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 修改表注释
ALTER TABLE users COMMENT='用户基础信息表';

-- 重置自增值
ALTER TABLE users AUTO_INCREMENT=1000;
DROP - 删除数据库对象 ​
sql
-- 删除索引
DROP INDEX idx_email ON users;

-- 删除视图
DROP VIEW IF EXISTS user_order_stats;

-- 删除表
DROP TABLE IF EXISTS temp_table;

-- 删除数据库
DROP DATABASE IF EXISTS old_database;
TRUNCATE - 快速清空表数据 ​
sql
-- 清空表数据(保留表结构)
TRUNCATE TABLE log_table;

-- TRUNCATE vs DELETE 的区别:
-- TRUNCATE: 更快,重置自增值,不能回滚,不触发触发器
-- DELETE: 较慢,保持自增值,可以回滚,触发触发器

设计原则: ​

  1. 命名规范:使用有意义的名称,遵循一致的命名约定

    sql
    -- 好的命名
    CREATE TABLE user_profiles (
        user_id INT,
        profile_image_url VARCHAR(500),
        created_at TIMESTAMP
    );
    
    -- 避免的命名
    CREATE TABLE t1 (
        col1 INT,
        col2 VARCHAR(500),
        col3 TIMESTAMP
    );
  2. 数据类型选择:根据数据特点选择合适的数据类型

    sql
    CREATE TABLE products (
        id INT UNSIGNED,              -- 正整数用UNSIGNED
        price DECIMAL(10,2),          -- 金额用DECIMAL保证精度
        description TEXT,             -- 长文本用TEXT
        is_active BOOLEAN,            -- 布尔值用BOOLEAN
        category_id TINYINT UNSIGNED, -- 小范围整数用TINYINT
        created_at TIMESTAMP          -- 时间戳用TIMESTAMP
    );
  3. 约束设计:合理使用主键、外键、唯一约束等

    sql
    CREATE TABLE order_items (
        id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
        order_id BIGINT UNSIGNED NOT NULL,
        product_id INT UNSIGNED NOT NULL,
        quantity SMALLINT UNSIGNED NOT NULL CHECK (quantity > 0),
        unit_price DECIMAL(10,2) NOT NULL CHECK (unit_price >= 0),
        
        UNIQUE KEY uk_order_product (order_id, product_id),
        FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE,
        FOREIGN KEY (product_id) REFERENCES products(id) ON DELETE RESTRICT
    );
  4. 索引策略:在创建表时考虑索引需求

    sql
    CREATE TABLE user_activities (
        id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
        user_id INT UNSIGNED NOT NULL,
        activity_type VARCHAR(50) NOT NULL,
        activity_data JSON,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        
        -- 为常用查询创建索引
        INDEX idx_user_id (user_id),
        INDEX idx_activity_type (activity_type),
        INDEX idx_created_at (created_at),
        INDEX idx_user_type_time (user_id, activity_type, created_at)
    );

2. 数据操作语言(DML - Data Manipulation Language) ​

DML 用于对数据库中的数据进行增删改操作,是日常数据库操作中使用最频繁的语言类型。

主要特点: ​

  • 数据操作:专注于数据内容的处理,不涉及结构变更
  • 事务性:DML 操作通常在事务中执行,支持回滚
  • 性能敏感:大量数据操作时需要考虑性能优化
  • 并发控制:需要处理多用户同时操作的并发问题

核心命令详解: ​

INSERT - 插入数据 ​

基本插入:

sql
-- 插入单条记录
INSERT INTO users (username, email, password_hash, full_name) 
VALUES ('john_doe', 'john@example.com', 'hashed_password', 'John Doe');

-- 插入多条记录(批量插入)
INSERT INTO users (username, email, password_hash, full_name) 
VALUES 
    ('alice', 'alice@example.com', 'hash1', 'Alice Smith'),
    ('bob', 'bob@example.com', 'hash2', 'Bob Johnson'),
    ('charlie', 'charlie@example.com', 'hash3', 'Charlie Brown');

-- 插入所有列(按表结构顺序)
INSERT INTO users 
VALUES (NULL, 'david', 'david@example.com', 'hash4', 'David Wilson', 
        '1990-05-15', 'M', 1, NOW(), NOW());

高级插入技巧:

sql
-- INSERT IGNORE:忽略重复键错误
INSERT IGNORE INTO users (username, email, password_hash) 
VALUES ('existing_user', 'existing@example.com', 'hash');

-- ON DUPLICATE KEY UPDATE:遇到重复键时更新
INSERT INTO users (username, email, password_hash, full_name) 
VALUES ('john_doe', 'john@example.com', 'new_hash', 'John Doe Updated')
ON DUPLICATE KEY UPDATE 
    password_hash = VALUES(password_hash),
    full_name = VALUES(full_name),
    updated_at = NOW();

-- 从查询结果插入
INSERT INTO user_backup (id, username, email, created_at)
SELECT id, username, email, created_at 
FROM users 
WHERE created_at < '2023-01-01';

-- 使用SET语法插入
INSERT INTO users 
SET username = 'emma', 
    email = 'emma@example.com', 
    password_hash = 'hash5',
    created_at = NOW();
UPDATE - 更新数据 ​

基本更新:

sql
-- 更新单个字段
UPDATE users 
SET full_name = 'John Smith' 
WHERE username = 'john_doe';

-- 更新多个字段
UPDATE users 
SET 
    full_name = 'Alice Johnson',
    phone = '+1-555-0123',
    updated_at = NOW()
WHERE id = 2;

-- 条件更新
UPDATE users 
SET status = 0 
WHERE last_login_at < DATE_SUB(NOW(), INTERVAL 1 YEAR);

高级更新技巧:

sql
-- 使用表达式更新
UPDATE orders 
SET total_amount = total_amount * 1.1 
WHERE status = 'pending' AND created_at > '2024-01-01';

-- 多表关联更新
UPDATE users u
INNER JOIN (
    SELECT user_id, COUNT(*) as order_count
    FROM orders 
    GROUP BY user_id
) o ON u.id = o.user_id
SET u.total_orders = o.order_count;

-- 使用CASE WHEN进行条件更新
UPDATE users 
SET status = CASE 
    WHEN last_login_at > DATE_SUB(NOW(), INTERVAL 30 DAY) THEN 1
    WHEN last_login_at > DATE_SUB(NOW(), INTERVAL 90 DAY) THEN 2
    ELSE 0
END;

-- 限制更新行数
UPDATE users 
SET status = 1 
WHERE status = 0 
ORDER BY last_login_at DESC 
LIMIT 100;
DELETE - 删除数据 ​

基本删除:

sql
-- 删除特定记录
DELETE FROM users 
WHERE username = 'john_doe';

-- 条件删除
DELETE FROM users 
WHERE status = 0 AND created_at < '2023-01-01';

-- 删除所有记录(保留表结构)
DELETE FROM temp_table;

高级删除技巧:

sql
-- 多表关联删除
DELETE u, o 
FROM users u
INNER JOIN orders o ON u.id = o.user_id
WHERE u.status = 0;

-- 使用子查询删除
DELETE FROM users 
WHERE id IN (
    SELECT user_id 
    FROM (
        SELECT user_id 
        FROM orders 
        WHERE status = 'cancelled' 
        GROUP BY user_id 
        HAVING COUNT(*) > 5
    ) AS subquery
);

-- 限制删除行数
DELETE FROM log_table 
WHERE created_at < DATE_SUB(NOW(), INTERVAL 30 DAY)
ORDER BY created_at 
LIMIT 1000;
REPLACE - 替换数据(MySQL特有) ​
sql
-- REPLACE:如果存在则删除后插入,不存在则直接插入
REPLACE INTO users (id, username, email, password_hash) 
VALUES (1, 'john_doe', 'john@example.com', 'new_hash');

-- 批量REPLACE
REPLACE INTO users (username, email, password_hash) 
VALUES 
    ('user1', 'user1@example.com', 'hash1'),
    ('user2', 'user2@example.com', 'hash2');

操作策略与最佳实践: ​

  1. 批量操作:尽量使用批量插入、更新来提高效率

    sql
    -- 好的做法:批量插入
    INSERT INTO products (name, price, category_id) VALUES
        ('Product A', 19.99, 1),
        ('Product B', 29.99, 1),
        ('Product C', 39.99, 2);
    
    -- 避免:逐条插入
    INSERT INTO products (name, price, category_id) VALUES ('Product A', 19.99, 1);
    INSERT INTO products (name, price, category_id) VALUES ('Product B', 29.99, 1);
    INSERT INTO products (name, price, category_id) VALUES ('Product C', 39.99, 2);
  2. 条件精确:UPDATE 和 DELETE 操作必须使用精确的 WHERE 条件

    sql
    -- 危险:可能影响所有记录
    UPDATE users SET status = 0;
    
    -- 安全:使用明确条件
    UPDATE users SET status = 0 WHERE last_login_at < '2023-01-01';
    
    -- 更安全:先查询确认影响范围
    SELECT COUNT(*) FROM users WHERE last_login_at < '2023-01-01';
    UPDATE users SET status = 0 WHERE last_login_at < '2023-01-01';
  3. 事务管理:重要操作应该在事务中进行

    sql
    START TRANSACTION;
    
    -- 转账操作示例
    UPDATE accounts SET balance = balance - 100 WHERE id = 1;
    UPDATE accounts SET balance = balance + 100 WHERE id = 2;
    
    -- 检查操作结果
    SELECT balance FROM accounts WHERE id IN (1, 2);
    
    -- 确认无误后提交
    COMMIT;
    -- 或者发现问题时回滚
    -- ROLLBACK;
  4. 性能监控:关注操作对数据库性能的影响

    sql
    -- 使用EXPLAIN分析更新语句
    EXPLAIN UPDATE users SET status = 1 WHERE created_at > '2024-01-01';
    
    -- 对于大量数据操作,分批处理
    UPDATE users SET status = 1 
    WHERE created_at > '2024-01-01' 
    AND id BETWEEN 1 AND 1000;
    
    UPDATE users SET status = 1 
    WHERE created_at > '2024-01-01' 
    AND id BETWEEN 1001 AND 2000;
  5. 数据完整性:确保操作不破坏数据完整性

    sql
    -- 使用约束确保数据有效性
    INSERT INTO orders (user_id, total_amount, status) 
    VALUES (1, 99.99, 'pending');
    
    -- 在删除前检查依赖关系
    SELECT COUNT(*) FROM orders WHERE user_id = 1;
    -- 如果有订单,可能需要先处理订单或使用软删除
    UPDATE users SET status = 0, deleted_at = NOW() WHERE id = 1;

3. 数据查询语言(DQL - Data Query Language) ​

DQL 专门用于从数据库中检索数据,是 SQL 中最复杂也是最强大的部分。

主要特点: ​

  • 只读操作:不会修改数据库中的数据
  • 灵活性强:支持复杂的查询条件和数据处理
  • 性能关键:查询性能直接影响应用响应速度
  • 结果集处理:可以对查询结果进行排序、分组、聚合等操作

核心查询详解: ​

基本SELECT查询 ​

简单查询:

sql
-- 查询所有列
SELECT * FROM users;

-- 查询指定列
SELECT username, email, created_at FROM users;

-- 使用别名
SELECT 
    username AS '用户名',
    email AS '邮箱地址',
    created_at AS '注册时间'
FROM users;

-- 查询常量和表达式
SELECT 
    username,
    'VIP' AS user_type,
    YEAR(created_at) AS register_year,
    DATEDIFF(NOW(), created_at) AS days_since_register
FROM users;

去重查询:

sql
-- 去除重复记录
SELECT DISTINCT status FROM users;

-- 多列去重
SELECT DISTINCT status, gender FROM users;

-- 统计不重复值的数量
SELECT COUNT(DISTINCT email) AS unique_emails FROM users;
WHERE条件查询 ​

基本条件:

sql
-- 等值查询
SELECT * FROM users WHERE status = 1;

-- 不等值查询
SELECT * FROM users WHERE status != 0;
SELECT * FROM users WHERE status <> 0;

-- 范围查询
SELECT * FROM orders WHERE total_amount BETWEEN 100 AND 500;
SELECT * FROM users WHERE created_at >= '2024-01-01';

-- NULL值查询
SELECT * FROM users WHERE phone IS NULL;
SELECT * FROM users WHERE phone IS NOT NULL;

模糊查询:

sql
-- LIKE模糊匹配
SELECT * FROM users WHERE username LIKE 'john%';     -- 以john开头
SELECT * FROM users WHERE username LIKE '%smith';   -- 以smith结尾
SELECT * FROM users WHERE username LIKE '%admin%';  -- 包含admin
SELECT * FROM users WHERE username LIKE 'user_';    -- user_后跟一个字符

-- 正则表达式匹配
SELECT * FROM users WHERE username REGEXP '^[a-z]+[0-9]+$';

-- 全文搜索(需要全文索引)
SELECT * FROM articles 
WHERE MATCH(title, content) AGAINST('MySQL 教程' IN NATURAL LANGUAGE MODE);

逻辑条件:

sql
-- AND条件
SELECT * FROM users 
WHERE status = 1 AND gender = 'M' AND created_at > '2024-01-01';

-- OR条件
SELECT * FROM users 
WHERE status = 0 OR last_login_at < '2023-01-01';

-- 复合条件
SELECT * FROM users 
WHERE (status = 1 OR status = 2) AND gender = 'F';

-- IN条件
SELECT * FROM users WHERE id IN (1, 3, 5, 7, 9);
SELECT * FROM users WHERE status IN ('active', 'pending');

-- NOT IN条件
SELECT * FROM users WHERE id NOT IN (1, 2, 3);
排序和分页 ​

ORDER BY排序:

sql
-- 单列排序
SELECT * FROM users ORDER BY created_at DESC;
SELECT * FROM users ORDER BY username ASC;

-- 多列排序
SELECT * FROM users 
ORDER BY status DESC, created_at ASC;

-- 使用表达式排序
SELECT username, email, created_at
FROM users 
ORDER BY CHAR_LENGTH(username), created_at DESC;

-- 自定义排序
SELECT * FROM orders 
ORDER BY FIELD(status, 'pending', 'paid', 'shipped', 'completed');

LIMIT分页:

sql
-- 限制结果数量
SELECT * FROM users ORDER BY created_at DESC LIMIT 10;

-- 分页查询
SELECT * FROM users ORDER BY id LIMIT 20 OFFSET 40;  -- 第3页,每页20条
SELECT * FROM users ORDER BY id LIMIT 40, 20;       -- MySQL特有语法

-- 获取最新的5个用户
SELECT * FROM users ORDER BY created_at DESC LIMIT 5;
聚合函数和分组 ​

聚合函数:

sql
-- 基本聚合函数
SELECT 
    COUNT(*) AS total_users,
    COUNT(phone) AS users_with_phone,
    AVG(YEAR(NOW()) - YEAR(birth_date)) AS avg_age,
    MIN(created_at) AS first_register,
    MAX(created_at) AS last_register
FROM users;

-- 条件聚合
SELECT 
    COUNT(CASE WHEN status = 1 THEN 1 END) AS active_users,
    COUNT(CASE WHEN status = 0 THEN 1 END) AS inactive_users,
    SUM(CASE WHEN gender = 'M' THEN 1 ELSE 0 END) AS male_count
FROM users;

GROUP BY分组:

sql
-- 基本分组
SELECT status, COUNT(*) AS user_count
FROM users 
GROUP BY status;

-- 多列分组
SELECT status, gender, COUNT(*) AS count
FROM users 
GROUP BY status, gender
ORDER BY status, gender;

-- 分组后排序
SELECT 
    YEAR(created_at) AS register_year,
    COUNT(*) AS user_count
FROM users 
GROUP BY YEAR(created_at)
ORDER BY register_year DESC;

HAVING条件:

sql
-- 分组后筛选
SELECT status, COUNT(*) AS user_count
FROM users 
GROUP BY status
HAVING COUNT(*) > 100;

-- 复杂HAVING条件
SELECT 
    user_id,
    COUNT(*) AS order_count,
    SUM(total_amount) AS total_spent
FROM orders 
GROUP BY user_id
HAVING COUNT(*) >= 5 AND SUM(total_amount) > 1000
ORDER BY total_spent DESC;

查询组件详解 ​

WHERE 子句 ​

WHERE 子句用于过滤记录,只返回满足条件的行。

比较操作符详解: ​

基本比较操作:

sql
-- 等于
SELECT * FROM users WHERE age = 25;
SELECT * FROM products WHERE status = 'active';

-- 不等于
SELECT * FROM users WHERE age != 25;
SELECT * FROM users WHERE age <> 25;

-- 大小比较
SELECT * FROM products WHERE price > 100;
SELECT * FROM users WHERE created_at >= '2024-01-01';
SELECT * FROM orders WHERE total_amount <= 1000;

范围和列表操作:

sql
-- BETWEEN:范围查询
SELECT * FROM users WHERE age BETWEEN 18 AND 65;
SELECT * FROM orders WHERE order_date BETWEEN '2024-01-01' AND '2024-12-31';
SELECT * FROM products WHERE price BETWEEN 50.00 AND 200.00;

-- IN:列表匹配
SELECT * FROM users WHERE city IN ('北京', '上海', '广州', '深圳');
SELECT * FROM products WHERE category_id IN (1, 3, 5, 7);
SELECT * FROM orders WHERE status IN ('pending', 'processing', 'shipped');

-- NOT IN:排除列表
SELECT * FROM users WHERE city NOT IN ('北京', '上海');
SELECT * FROM products WHERE id NOT IN (SELECT product_id FROM discontinued_products);

模式匹配:

sql
-- LIKE:模式匹配
SELECT * FROM users WHERE username LIKE 'admin%';     -- 以admin开头
SELECT * FROM users WHERE email LIKE '%@gmail.com';  -- 以@gmail.com结尾
SELECT * FROM products WHERE name LIKE '%手机%';      -- 包含"手机"
SELECT * FROM users WHERE phone LIKE '138________';  -- 138开头的11位号码

-- REGEXP:正则表达式匹配
SELECT * FROM users WHERE email REGEXP '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$';
SELECT * FROM products WHERE sku REGEXP '^[A-Z]{2}[0-9]{4}$';

空值处理:

sql
-- IS NULL:查找空值
SELECT * FROM users WHERE phone IS NULL;
SELECT * FROM orders WHERE shipped_date IS NULL;

-- IS NOT NULL:查找非空值
SELECT * FROM users WHERE email IS NOT NULL;
SELECT * FROM products WHERE description IS NOT NULL;

-- COALESCE:处理空值
SELECT username, COALESCE(phone, '未提供') as phone_display FROM users;

逻辑操作符详解: ​

sql
-- AND:所有条件都必须满足
SELECT * FROM users 
WHERE age >= 18 
  AND city = '北京' 
  AND status = 'active';

-- OR:任一条件满足即可
SELECT * FROM products 
WHERE category = '电子产品' 
   OR category = '数码配件' 
   OR price < 100;

-- NOT:否定条件
SELECT * FROM users WHERE NOT (age < 18 OR status = 'inactive');

-- 复杂逻辑组合
SELECT * FROM orders 
WHERE (status = 'pending' OR status = 'processing') 
  AND total_amount > 500 
  AND (payment_method = '支付宝' OR payment_method = '微信支付');

-- 使用括号控制优先级
SELECT * FROM products 
WHERE (category = '服装' AND price > 200) 
   OR (category = '鞋类' AND price > 300);

ORDER BY 子句 ​

ORDER BY 用于对结果集进行排序。

基本排序: ​

sql
-- 单字段排序
SELECT * FROM users ORDER BY age;           -- 默认升序
SELECT * FROM users ORDER BY age ASC;       -- 明确指定升序
SELECT * FROM users ORDER BY age DESC;      -- 降序
SELECT * FROM products ORDER BY price DESC; -- 按价格降序

-- 多字段排序
SELECT * FROM users 
ORDER BY city ASC, age DESC, username ASC;

SELECT * FROM orders 
ORDER BY status, order_date DESC, total_amount DESC;

高级排序: ​

sql
-- 按表达式排序
SELECT *, (price * discount) as final_price 
FROM products 
ORDER BY final_price DESC;

-- 按函数结果排序
SELECT * FROM users ORDER BY CHAR_LENGTH(username) DESC;
SELECT * FROM orders ORDER BY YEAR(order_date), MONTH(order_date);

-- 条件排序(CASE WHEN)
SELECT * FROM orders 
ORDER BY 
  CASE status 
    WHEN 'urgent' THEN 1
    WHEN 'processing' THEN 2
    WHEN 'pending' THEN 3
    ELSE 4
  END,
  order_date DESC;

-- 自定义排序顺序
SELECT * FROM products 
ORDER BY FIELD(category, '热销', '新品', '促销', '普通');

-- NULL值排序控制
SELECT * FROM users ORDER BY phone IS NULL, phone;  -- NULL值排在最后
SELECT * FROM users ORDER BY phone IS NOT NULL DESC, phone; -- NULL值排在最前

GROUP BY 子句 ​

GROUP BY 用于将结果集按一个或多个字段进行分组。

基本分组: ​

sql
-- 单字段分组
SELECT city, COUNT(*) as user_count 
FROM users 
GROUP BY city;

SELECT category, AVG(price) as avg_price 
FROM products 
GROUP BY category;

-- 多字段分组
SELECT city, gender, COUNT(*) as count 
FROM users 
GROUP BY city, gender;

SELECT 
  YEAR(order_date) as year,
  MONTH(order_date) as month,
  COUNT(*) as order_count,
  SUM(total_amount) as total_sales
FROM orders 
GROUP BY YEAR(order_date), MONTH(order_date);

聚合函数应用: ​

sql
-- 常用聚合函数
SELECT 
  category,
  COUNT(*) as product_count,           -- 计数
  AVG(price) as avg_price,            -- 平均值
  MIN(price) as min_price,            -- 最小值
  MAX(price) as max_price,            -- 最大值
  SUM(stock) as total_stock,          -- 求和
  STDDEV(price) as price_stddev       -- 标准差
FROM products 
GROUP BY category;

-- 字符串聚合
SELECT 
  category,
  GROUP_CONCAT(name ORDER BY price DESC SEPARATOR '; ') as products
FROM products 
GROUP BY category;

-- 条件聚合
SELECT 
  city,
  COUNT(*) as total_users,
  COUNT(CASE WHEN age >= 18 THEN 1 END) as adult_users,
  COUNT(CASE WHEN gender = 'M' THEN 1 END) as male_users,
  AVG(CASE WHEN status = 'active' THEN age END) as avg_active_age
FROM users 
GROUP BY city;

WITH ROLLUP: ​

sql
-- 生成小计和总计
SELECT 
  category,
  subcategory,
  COUNT(*) as product_count,
  SUM(price) as total_value
FROM products 
GROUP BY category, subcategory WITH ROLLUP;

-- 销售报表示例
SELECT 
  YEAR(order_date) as year,
  QUARTER(order_date) as quarter,
  SUM(total_amount) as sales
FROM orders 
GROUP BY YEAR(order_date), QUARTER(order_date) WITH ROLLUP;

HAVING 子句 ​

HAVING 用于过滤分组后的结果,类似于 WHERE,但作用于分组。

基本用法: ​

sql
-- 过滤分组结果
SELECT city, COUNT(*) as user_count 
FROM users 
GROUP BY city 
HAVING COUNT(*) > 100;  -- 只显示用户数超过100的城市

SELECT category, AVG(price) as avg_price 
FROM products 
GROUP BY category 
HAVING AVG(price) > 500;  -- 只显示平均价格超过500的分类

复杂HAVING条件: ​

sql
-- 多个聚合条件
SELECT 
  category,
  COUNT(*) as product_count,
  AVG(price) as avg_price,
  MAX(price) as max_price
FROM products 
GROUP BY category 
HAVING COUNT(*) >= 5 
   AND AVG(price) > 100 
   AND MAX(price) < 1000;

-- 使用逻辑操作符
SELECT 
  city,
  COUNT(*) as user_count,
  AVG(age) as avg_age
FROM users 
GROUP BY city 
HAVING (COUNT(*) > 50 AND AVG(age) > 25) 
    OR (COUNT(*) > 100);

-- 结合WHERE和HAVING
SELECT 
  category,
  COUNT(*) as active_product_count,
  AVG(price) as avg_price
FROM products 
WHERE status = 'active'  -- 先过滤记录
GROUP BY category 
HAVING COUNT(*) > 10     -- 再过滤分组
   AND AVG(price) BETWEEN 100 AND 1000;

执行顺序说明: ​

sql
-- SQL执行顺序示例
SELECT 
  category,                    -- 5. 选择字段
  COUNT(*) as product_count,   -- 5. 计算聚合
  AVG(price) as avg_price      -- 5. 计算聚合
FROM products                  -- 1. 确定数据源
WHERE status = 'active'        -- 2. 过滤行
GROUP BY category              -- 3. 分组
HAVING COUNT(*) > 5            -- 4. 过滤分组
ORDER BY avg_price DESC        -- 6. 排序
LIMIT 10;                      -- 7. 限制结果数量

/*
执行顺序:
1. FROM - 确定数据源
2. WHERE - 过滤原始数据行
3. GROUP BY - 对数据进行分组
4. HAVING - 过滤分组后的结果
5. SELECT - 选择和计算字段
6. ORDER BY - 对结果排序
7. LIMIT - 限制返回的行数
*/

连接查询详解 ​

连接查询用于从多个表中获取相关数据,是SQL中最重要的功能之一。

内连接(INNER JOIN) ​

内连接只返回两个表中都存在匹配的记录,是最常用的连接类型。

基本语法: ​

sql
-- 标准语法
SELECT columns
FROM table1
INNER JOIN table2 ON table1.column = table2.column;

-- 简化语法(隐式连接)
SELECT columns
FROM table1, table2
WHERE table1.column = table2.column;

实际应用示例: ​

sql
-- 查询用户及其订单信息
SELECT 
    u.username,
    u.email,
    o.order_id,
    o.total_amount,
    o.order_date
FROM users u
INNER JOIN orders o ON u.user_id = o.user_id;

-- 查询商品及其分类信息
SELECT 
    p.product_name,
    p.price,
    c.category_name,
    c.description as category_desc
FROM products p
INNER JOIN categories c ON p.category_id = c.category_id
WHERE p.status = 'active';

-- 多表连接
SELECT 
    u.username,
    o.order_id,
    oi.product_id,
    p.product_name,
    oi.quantity,
    oi.unit_price
FROM users u
INNER JOIN orders o ON u.user_id = o.user_id
INNER JOIN order_items oi ON o.order_id = oi.order_id
INNER JOIN products p ON oi.product_id = p.product_id
WHERE o.order_date >= '2024-01-01';

左外连接(LEFT JOIN) ​

左外连接返回左表的所有记录,以及右表中匹配的记录。如果右表没有匹配,则显示 NULL。

sql
-- 查询所有用户及其订单(包括没有订单的用户)
SELECT 
    u.user_id,
    u.username,
    u.email,
    o.order_id,
    o.total_amount,
    o.order_date
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id;

-- 查询所有分类及其商品数量(包括没有商品的分类)
SELECT 
    c.category_name,
    COUNT(p.product_id) as product_count,
    COALESCE(AVG(p.price), 0) as avg_price
FROM categories c
LEFT JOIN products p ON c.category_id = p.category_id
GROUP BY c.category_id, c.category_name;

-- 查找没有订单的用户
SELECT 
    u.user_id,
    u.username,
    u.email
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
WHERE o.order_id IS NULL;

右外连接(RIGHT JOIN) ​

右外连接返回右表的所有记录,以及左表中匹配的记录。如果左表没有匹配,则显示 NULL。

sql
-- 查询所有订单及其用户信息(包括可能的孤立订单)
SELECT 
    u.username,
    u.email,
    o.order_id,
    o.total_amount,
    o.order_date
FROM users u
RIGHT JOIN orders o ON u.user_id = o.user_id;

-- 查询所有商品及其分类(包括可能的孤立商品)
SELECT 
    p.product_name,
    p.price,
    c.category_name
FROM categories c
RIGHT JOIN products p ON c.category_id = p.category_id;

全外连接(FULL OUTER JOIN) ​

MySQL 不直接支持 FULL OUTER JOIN,但可以通过 UNION 实现。

sql
-- 使用UNION模拟全外连接
SELECT 
    u.user_id,
    u.username,
    o.order_id,
    o.total_amount
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id

UNION

SELECT 
    u.user_id,
    u.username,
    o.order_id,
    o.total_amount
FROM users u
RIGHT JOIN orders o ON u.user_id = o.user_id
WHERE u.user_id IS NULL;

-- 更简洁的写法(MySQL 8.0+)
SELECT 
    COALESCE(u.user_id, o.user_id) as user_id,
    u.username,
    o.order_id,
    o.total_amount
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id

UNION ALL

SELECT 
    o.user_id,
    NULL as username,
    o.order_id,
    o.total_amount
FROM orders o
LEFT JOIN users u ON o.user_id = u.user_id
WHERE u.user_id IS NULL;

交叉连接(CROSS JOIN) ​

交叉连接返回两个表的笛卡尔积,每个左表记录与每个右表记录组合。

sql
-- 基本交叉连接
SELECT 
    u.username,
    p.product_name,
    p.price
FROM users u
CROSS JOIN products p
WHERE u.city = '北京' AND p.category_id = 1;

-- 生成所有可能的组合
SELECT 
    s.size_name,
    c.color_name,
    CONCAT(s.size_name, '-', c.color_name) as variant
FROM sizes s
CROSS JOIN colors c;

-- 生成日期序列与产品的组合
SELECT 
    d.date,
    p.product_id,
    p.product_name
FROM (
    SELECT DATE('2024-01-01') + INTERVAL n DAY as date
    FROM (
        SELECT 0 as n UNION SELECT 1 UNION SELECT 2 UNION SELECT 3
        UNION SELECT 4 UNION SELECT 5 UNION SELECT 6
    ) numbers
) d
CROSS JOIN products p
WHERE p.status = 'active';

自连接(Self JOIN) ​

自连接是表与自身进行连接,通常用于处理层次结构数据。

sql
-- 查询员工及其直接上级
SELECT 
    e1.employee_id,
    e1.employee_name,
    e1.position,
    e2.employee_name as manager_name,
    e2.position as manager_position
FROM employees e1
LEFT JOIN employees e2 ON e1.manager_id = e2.employee_id;

-- 查询同一部门的员工对比
SELECT 
    e1.employee_name as employee1,
    e2.employee_name as employee2,
    e1.department,
    e1.salary as salary1,
    e2.salary as salary2
FROM employees e1
INNER JOIN employees e2 ON e1.department = e2.department
WHERE e1.employee_id < e2.employee_id  -- 避免重复和自己与自己比较
  AND ABS(e1.salary - e2.salary) < 5000;

-- 查询分类的层次结构
SELECT 
    c1.category_id,
    c1.category_name,
    c1.level,
    c2.category_name as parent_category
FROM categories c1
LEFT JOIN categories c2 ON c1.parent_id = c2.category_id
ORDER BY c1.level, c1.category_name;

-- 查找相似价格的商品
SELECT 
    p1.product_name as product1,
    p1.price as price1,
    p2.product_name as product2,
    p2.price as price2,
    ABS(p1.price - p2.price) as price_diff
FROM products p1
INNER JOIN products p2 ON p1.category_id = p2.category_id
WHERE p1.product_id < p2.product_id
  AND ABS(p1.price - p2.price) <= 50
ORDER BY price_diff;

复杂连接查询示例 ​

1. 电商订单分析 ​

sql
-- 查询用户的完整订单信息
SELECT 
    u.username,
    u.email,
    o.order_id,
    o.order_date,
    o.status as order_status,
    COUNT(oi.item_id) as item_count,
    SUM(oi.quantity * oi.unit_price) as calculated_total,
    o.total_amount,
    GROUP_CONCAT(
        CONCAT(p.product_name, '(', oi.quantity, ')')
        ORDER BY oi.item_id
        SEPARATOR ', '
    ) as order_items
FROM users u
INNER JOIN orders o ON u.user_id = o.user_id
INNER JOIN order_items oi ON o.order_id = oi.order_id
INNER JOIN products p ON oi.product_id = p.product_id
WHERE o.order_date >= '2024-01-01'
GROUP BY u.user_id, o.order_id
HAVING item_count > 1
ORDER BY o.order_date DESC;

2. 库存和销售分析 ​

sql
-- 分析商品的库存和销售情况
SELECT 
    c.category_name,
    p.product_name,
    p.stock as current_stock,
    COALESCE(sales.total_sold, 0) as total_sold,
    COALESCE(sales.total_revenue, 0) as total_revenue,
    COALESCE(sales.avg_price, p.price) as avg_selling_price,
    p.price as current_price,
    CASE 
        WHEN p.stock = 0 THEN '缺货'
        WHEN p.stock < 10 THEN '库存不足'
        WHEN p.stock < 50 THEN '库存正常'
        ELSE '库存充足'
    END as stock_status
FROM categories c
INNER JOIN products p ON c.category_id = p.category_id
LEFT JOIN (
    SELECT 
        oi.product_id,
        SUM(oi.quantity) as total_sold,
        SUM(oi.quantity * oi.unit_price) as total_revenue,
        AVG(oi.unit_price) as avg_price
    FROM order_items oi
    INNER JOIN orders o ON oi.order_id = o.order_id
    WHERE o.status = 'completed'
      AND o.order_date >= DATE_SUB(NOW(), INTERVAL 3 MONTH)
    GROUP BY oi.product_id
) sales ON p.product_id = sales.product_id
WHERE p.status = 'active'
ORDER BY c.category_name, total_revenue DESC;

3. 用户行为分析 ​

sql
-- 分析用户的购买行为和偏好
SELECT 
    u.user_id,
    u.username,
    u.registration_date,
    profile.order_count,
    profile.total_spent,
    profile.avg_order_value,
    profile.favorite_category,
    profile.last_order_date,
    DATEDIFF(NOW(), profile.last_order_date) as days_since_last_order,
    CASE 
        WHEN profile.total_spent > 10000 THEN 'VIP客户'
        WHEN profile.total_spent > 5000 THEN '重要客户'
        WHEN profile.total_spent > 1000 THEN '普通客户'
        ELSE '新客户'
    END as customer_level
FROM users u
LEFT JOIN (
    SELECT 
        o.user_id,
        COUNT(o.order_id) as order_count,
        SUM(o.total_amount) as total_spent,
        AVG(o.total_amount) as avg_order_value,
        MAX(o.order_date) as last_order_date,
        (
            SELECT c.category_name
            FROM order_items oi2
            INNER JOIN orders o2 ON oi2.order_id = o2.order_id
            INNER JOIN products p2 ON oi2.product_id = p2.product_id
            INNER JOIN categories c ON p2.category_id = c.category_id
            WHERE o2.user_id = o.user_id
            GROUP BY c.category_id
            ORDER BY SUM(oi2.quantity) DESC
            LIMIT 1
        ) as favorite_category
    FROM orders o
    WHERE o.status = 'completed'
    GROUP BY o.user_id
) profile ON u.user_id = profile.user_id
ORDER BY profile.total_spent DESC;

连接查询优化技巧 ​

1. 使用适当的索引 ​

sql
-- 确保连接字段有索引
CREATE INDEX idx_orders_user_id ON orders(user_id);
CREATE INDEX idx_order_items_order_id ON order_items(order_id);
CREATE INDEX idx_order_items_product_id ON order_items(product_id);

-- 复合索引优化多字段连接
CREATE INDEX idx_orders_user_date ON orders(user_id, order_date);

2. 使用表别名简化查询 ​

sql
-- 使用有意义的别名
SELECT 
    usr.username,
    ord.order_date,
    prd.product_name
FROM users usr
INNER JOIN orders ord ON usr.user_id = ord.user_id
INNER JOIN order_items itm ON ord.order_id = itm.order_id
INNER JOIN products prd ON itm.product_id = prd.product_id;

3. 合理使用WHERE条件 ​

sql
-- 在连接前过滤数据
SELECT 
    u.username,
    o.order_id,
    o.total_amount
FROM users u
INNER JOIN (
    SELECT * FROM orders 
    WHERE order_date >= '2024-01-01' 
      AND status = 'completed'
) o ON u.user_id = o.user_id
WHERE u.status = 'active';
子查询 ​

标量子查询:

sql
-- 返回单个值的子查询
SELECT username, email
FROM users 
WHERE created_at = (SELECT MAX(created_at) FROM users);

-- 在SELECT中使用子查询
SELECT 
    username,
    email,
    (SELECT COUNT(*) FROM orders WHERE user_id = users.id) AS order_count
FROM users;

列表子查询:

sql
-- IN子查询
SELECT * FROM users 
WHERE id IN (
    SELECT DISTINCT user_id 
    FROM orders 
    WHERE total_amount > 500
);

-- EXISTS子查询
SELECT * FROM users u
WHERE EXISTS (
    SELECT 1 FROM orders o 
    WHERE o.user_id = u.id AND o.status = 'completed'
);

-- NOT EXISTS子查询
SELECT * FROM users u
WHERE NOT EXISTS (
    SELECT 1 FROM orders o 
    WHERE o.user_id = u.id
);

表子查询:

sql
-- 在FROM中使用子查询
SELECT 
    avg_order.user_id,
    avg_order.avg_amount,
    u.username
FROM (
    SELECT 
        user_id, 
        AVG(total_amount) AS avg_amount
    FROM orders 
    GROUP BY user_id
    HAVING AVG(total_amount) > 200
) AS avg_order
JOIN users u ON avg_order.user_id = u.id;
窗口函数(MySQL 8.0+) ​
sql
-- ROW_NUMBER:行号
SELECT 
    username,
    created_at,
    ROW_NUMBER() OVER (ORDER BY created_at) AS row_num
FROM users;

-- RANK:排名
SELECT 
    user_id,
    total_amount,
    RANK() OVER (ORDER BY total_amount DESC) AS amount_rank
FROM orders;

-- 分区窗口函数
SELECT 
    user_id,
    order_date,
    total_amount,
    SUM(total_amount) OVER (
        PARTITION BY user_id 
        ORDER BY order_date 
        ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
    ) AS running_total
FROM orders;
集合操作 ​

UNION:

sql
-- 合并查询结果
SELECT username, email FROM users WHERE status = 1
UNION
SELECT username, email FROM users WHERE created_at > '2024-01-01';

-- UNION ALL:包含重复记录
SELECT user_id FROM orders WHERE order_date >= '2024-01-01'
UNION ALL
SELECT user_id FROM reviews WHERE review_date >= '2024-01-01';

查询优化策略: ​

  1. 索引优化:确保查询条件能够有效使用索引

    sql
    -- 好的做法:使用索引列作为查询条件
    SELECT * FROM users WHERE email = 'john@example.com';
    
    -- 避免:在索引列上使用函数
    SELECT * FROM users WHERE UPPER(email) = 'JOHN@EXAMPLE.COM';
    
    -- 改进:使用函数索引或调整查询
    SELECT * FROM users WHERE email = LOWER('JOHN@EXAMPLE.COM');
  2. 条件优化:将选择性高的条件放在前面

    sql
    -- 好的做法:选择性高的条件在前
    SELECT * FROM users 
    WHERE email = 'specific@example.com' AND status = 1;
    
    -- 避免:选择性低的条件在前
    SELECT * FROM users 
    WHERE status = 1 AND email = 'specific@example.com';
  3. 字段选择:只查询需要的字段,避免使用 SELECT *

    sql
    -- 好的做法:明确指定需要的字段
    SELECT id, username, email FROM users WHERE status = 1;
    
    -- 避免:查询所有字段
    SELECT * FROM users WHERE status = 1;
  4. 连接优化:合理使用不同类型的 JOIN

    sql
    -- 使用适当的JOIN类型
    SELECT u.username, COUNT(o.id) as order_count
    FROM users u
    LEFT JOIN orders o ON u.id = o.user_id
    GROUP BY u.id, u.username;
    
    -- 避免笛卡尔积
    SELECT u.username, o.order_no
    FROM users u, orders o
    WHERE u.id = o.user_id;  -- 确保有连接条件

4. 数据控制语言(DCL - Data Control Language) ​

DCL 用于控制数据库的访问权限和安全性,主要涉及用户权限的管理。

主要特点: ​

  • 安全管理:控制用户对数据库对象的访问权限
  • 权限粒度:可以精细控制到表、列、操作级别
  • 用户管理:创建和管理数据库用户
  • 即时生效:权限变更通常立即生效

核心命令详解: ​

用户管理 ​

创建用户:

sql
-- 创建基本用户
CREATE USER 'username'@'localhost' IDENTIFIED BY 'password';

-- 创建用户并指定认证插件
CREATE USER 'username'@'192.168.1.%' IDENTIFIED WITH mysql_native_password BY 'password';

-- 创建用户并设置密码过期策略
CREATE USER 'username'@'%' 
IDENTIFIED BY 'password' 
PASSWORD EXPIRE INTERVAL 90 DAY;

-- 创建用户并设置账户锁定策略
CREATE USER 'username'@'localhost' 
IDENTIFIED BY 'password' 
ACCOUNT LOCK;

修改用户:

sql
-- 修改用户密码
ALTER USER 'username'@'localhost' IDENTIFIED BY 'new_password';

-- 修改用户认证插件
ALTER USER 'username'@'localhost' IDENTIFIED WITH caching_sha2_password BY 'password';

-- 解锁用户账户
ALTER USER 'username'@'localhost' ACCOUNT UNLOCK;

-- 重命名用户
RENAME USER 'old_username'@'localhost' TO 'new_username'@'localhost';

删除用户:

sql
-- 删除单个用户
DROP USER 'username'@'localhost';

-- 删除多个用户
DROP USER 'user1'@'localhost', 'user2'@'%';
权限管理 ​

授予权限:

sql
-- 授予特定表的权限
GRANT SELECT, INSERT, UPDATE ON database_name.table_name TO 'username'@'localhost';

-- 授予特定数据库的所有权限
GRANT ALL PRIVILEGES ON database_name.* TO 'username'@'localhost';

-- 授予所有数据库的所有权限(超级用户)
GRANT ALL PRIVILEGES ON *.* TO 'admin'@'localhost' WITH GRANT OPTION;

-- 授予特定列的权限
GRANT SELECT (id, username, email), UPDATE (email, phone) 
ON database_name.users TO 'username'@'localhost';

-- 授予存储过程的执行权限
GRANT EXECUTE ON PROCEDURE database_name.procedure_name TO 'username'@'localhost';

撤销权限:

sql
-- 撤销特定表的权限
REVOKE INSERT, UPDATE ON database_name.table_name FROM 'username'@'localhost';

-- 撤销特定数据库的所有权限
REVOKE ALL PRIVILEGES ON database_name.* FROM 'username'@'localhost';

-- 撤销授权权限
REVOKE GRANT OPTION ON database_name.* FROM 'username'@'localhost';

查看权限:

sql
-- 查看当前用户权限
SHOW GRANTS;

-- 查看特定用户权限
SHOW GRANTS FOR 'username'@'localhost';

-- 查看所有用户
SELECT user, host FROM mysql.user;

-- 查看权限详情
SELECT * FROM information_schema.user_privileges WHERE grantee LIKE "'username'%";
角色管理(MySQL 8.0+) ​
sql
-- 创建角色
CREATE ROLE 'app_read', 'app_write', 'app_admin';

-- 为角色授权
GRANT SELECT ON app_db.* TO 'app_read';
GRANT INSERT, UPDATE, DELETE ON app_db.* TO 'app_write';
GRANT ALL PRIVILEGES ON app_db.* TO 'app_admin';

-- 将角色分配给用户
GRANT 'app_read' TO 'reader'@'localhost';
GRANT 'app_write', 'app_read' TO 'editor'@'localhost';
GRANT 'app_admin' TO 'admin'@'localhost';

-- 激活角色
SET ROLE 'app_read';
SET ROLE ALL;  -- 激活所有被授予的角色

-- 设置默认角色
SET DEFAULT ROLE 'app_read' TO 'reader'@'localhost';
SET DEFAULT ROLE ALL TO 'editor'@'localhost';

-- 撤销角色
REVOKE 'app_write' FROM 'editor'@'localhost';

-- 删除角色
DROP ROLE 'app_read', 'app_write', 'app_admin';

权限管理策略与最佳实践: ​

  1. 最小权限原则:只授予必要的权限

    sql
    -- 好的做法:只授予应用所需的最小权限
    CREATE USER 'app_user'@'%' IDENTIFIED BY 'password';
    GRANT SELECT, INSERT, UPDATE ON app_db.users TO 'app_user'@'%';
    GRANT SELECT ON app_db.products TO 'app_user'@'%';
    
    -- 避免:授予过多权限
    GRANT ALL PRIVILEGES ON app_db.* TO 'app_user'@'%';
  2. 角色分离:不同角色使用不同账户

    sql
    -- 创建只读用户
    CREATE USER 'app_readonly'@'%' IDENTIFIED BY 'password';
    GRANT SELECT ON app_db.* TO 'app_readonly'@'%';
    
    -- 创建读写用户
    CREATE USER 'app_readwrite'@'%' IDENTIFIED BY 'password';
    GRANT SELECT, INSERT, UPDATE, DELETE ON app_db.* TO 'app_readwrite'@'%';
    
    -- 创建管理员用户
    CREATE USER 'app_admin'@'localhost' IDENTIFIED BY 'password';
    GRANT ALL PRIVILEGES ON app_db.* TO 'app_admin'@'localhost';
  3. 定期审计:定期检查和更新权限设置

    sql
    -- 查看所有用户及其权限
    SELECT user, host FROM mysql.user;
    
    -- 对每个用户执行
    SHOW GRANTS FOR 'username'@'host';
    
    -- 撤销不必要的权限
    REVOKE INSERT, UPDATE, DELETE ON app_db.logs FROM 'app_user'@'%';
  4. 密码策略:实施强密码策略

    sql
    -- 设置密码过期策略
    ALTER USER 'username'@'localhost' PASSWORD EXPIRE INTERVAL 90 DAY;
    
    -- 设置密码历史策略
    ALTER USER 'username'@'localhost' PASSWORD HISTORY 5;
    
    -- 设置密码重用策略
    ALTER USER 'username'@'localhost' PASSWORD REUSE INTERVAL 365 DAY;
    
    -- 设置密码强度策略
    ALTER USER 'username'@'localhost' 
    IDENTIFIED BY 'StrongP@ssw0rd' 
    PASSWORD REQUIRE CURRENT;
  5. 网络安全:限制连接来源

    sql
    -- 限制用户只能从特定IP连接
    CREATE USER 'app_user'@'192.168.1.10' IDENTIFIED BY 'password';
    
    -- 限制用户只能从特定网段连接
    CREATE USER 'app_user'@'192.168.1.%' IDENTIFIED BY 'password';
    
    -- 限制用户只能从本地连接
    CREATE USER 'admin'@'localhost' IDENTIFIED BY 'password';

5. 事务控制语言(TCL - Transaction Control Language) ​

TCL 用于管理数据库事务,确保数据的一致性和完整性。

主要特点: ​

  • 原子性:事务中的操作要么全部成功,要么全部失败
  • 一致性:事务执行前后数据库状态保持一致
  • 隔离性:并发事务之间相互隔离
  • 持久性:已提交的事务永久保存

核心命令详解: ​

基本事务控制 ​

开始事务:

sql
-- 方式1:使用START TRANSACTION
START TRANSACTION;

-- 方式2:使用BEGIN
BEGIN;

-- 方式3:设置事务特性
START TRANSACTION READ WRITE;
START TRANSACTION READ ONLY;
START TRANSACTION WITH CONSISTENT SNAPSHOT;

提交事务:

sql
-- 提交当前事务
COMMIT;

-- 提交并开始新事务(MySQL特有)
COMMIT AND CHAIN;

回滚事务:

sql
-- 回滚当前事务
ROLLBACK;

-- 回滚并开始新事务
ROLLBACK AND CHAIN;
保存点管理 ​
sql
-- 设置保存点
START TRANSACTION;
INSERT INTO users (username, email) VALUES ('user1', 'user1@example.com');
SAVEPOINT sp1;

INSERT INTO users (username, email) VALUES ('user2', 'user2@example.com');
SAVEPOINT sp2;

UPDATE users SET email = 'newemail@example.com' WHERE username = 'user1';

-- 回滚到保存点
ROLLBACK TO SAVEPOINT sp2;  -- 只回滚UPDATE操作

-- 释放保存点
RELEASE SAVEPOINT sp1;

-- 提交事务
COMMIT;
事务隔离级别 ​
sql
-- 查看当前隔离级别
SELECT @@transaction_isolation;

-- 设置会话级隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;

-- 设置全局隔离级别
SET GLOBAL TRANSACTION ISOLATION LEVEL REPEATABLE READ;

-- 为下一个事务设置隔离级别
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
START TRANSACTION;
-- 事务操作
COMMIT;
自动提交控制 ​
sql
-- 查看自动提交状态
SELECT @@autocommit;

-- 关闭自动提交
SET autocommit = 0;

-- 开启自动提交
SET autocommit = 1;

-- 在关闭自动提交模式下的操作
SET autocommit = 0;
INSERT INTO users (username, email) VALUES ('user3', 'user3@example.com');
UPDATE users SET status = 1 WHERE username = 'user3';
COMMIT;  -- 手动提交

事务应用场景与示例: ​

1. 银行转账事务 ​
sql
START TRANSACTION;

-- 检查账户余额
SELECT balance FROM accounts WHERE account_id = 'A001' FOR UPDATE;
SELECT balance FROM accounts WHERE account_id = 'A002' FOR UPDATE;

-- 转账操作
UPDATE accounts 
SET balance = balance - 1000 
WHERE account_id = 'A001' AND balance >= 1000;

-- 检查是否成功扣款
IF ROW_COUNT() = 0 THEN
    ROLLBACK;
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '余额不足';
END IF;

-- 增加目标账户余额
UPDATE accounts 
SET balance = balance + 1000 
WHERE account_id = 'A002';

-- 记录转账日志
INSERT INTO transfer_log (from_account, to_account, amount, transfer_time)
VALUES ('A001', 'A002', 1000, NOW());

COMMIT;
2. 订单处理事务 ​
sql
START TRANSACTION;

-- 创建订单
INSERT INTO orders (user_id, total_amount, status) 
VALUES (1, 299.99, 'pending');

SET @order_id = LAST_INSERT_ID();

-- 添加订单项
INSERT INTO order_items (order_id, product_id, quantity, unit_price)
VALUES 
    (@order_id, 101, 2, 99.99),
    (@order_id, 102, 1, 99.99);

-- 更新库存
UPDATE products SET stock = stock - 2 WHERE id = 101 AND stock >= 2;
UPDATE products SET stock = stock - 1 WHERE id = 102 AND stock >= 1;

-- 检查库存更新是否成功
IF (SELECT COUNT(*) FROM products WHERE id IN (101, 102) AND stock < 0) > 0 THEN
    ROLLBACK;
    SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '库存不足';
END IF;

-- 更新用户积分
UPDATE users SET points = points + 30 WHERE id = 1;

COMMIT;
3. 批量数据处理事务 ​
sql
START TRANSACTION;

-- 设置保存点
SAVEPOINT batch_start;

-- 批量插入用户数据
INSERT INTO users (username, email, created_at)
SELECT 
    CONCAT('user_', id),
    CONCAT('user_', id, '@example.com'),
    NOW()
FROM temp_user_data;

-- 检查插入结果
IF ROW_COUNT() != (SELECT COUNT(*) FROM temp_user_data) THEN
    ROLLBACK TO SAVEPOINT batch_start;
    -- 处理错误或重试
END IF;

-- 批量更新用户状态
UPDATE users SET status = 1 
WHERE username LIKE 'user_%' AND created_at >= CURDATE();

-- 清理临时数据
DELETE FROM temp_user_data;

COMMIT;

事务管理策略与最佳实践: ​

  1. 事务边界:明确定义事务的开始和结束

    sql
    -- 好的做法:明确的事务边界
    START TRANSACTION;
    -- 相关的业务操作
    INSERT INTO orders (...);
    INSERT INTO order_items (...);
    UPDATE inventory (...);
    COMMIT;
    
    -- 避免:事务范围过大
    START TRANSACTION;
    -- 大量不相关的操作
    -- 长时间运行的查询
    COMMIT;
  2. 错误处理:合理处理事务中的错误情况

    sql
    START TRANSACTION;
    
    -- 使用条件检查
    IF (SELECT COUNT(*) FROM users WHERE id = @user_id) = 0 THEN
        ROLLBACK;
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '用户不存在';
    END IF;
    
    -- 检查操作结果
    UPDATE accounts SET balance = balance - @amount WHERE id = @account_id;
    IF ROW_COUNT() = 0 THEN
        ROLLBACK;
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '账户更新失败';
    END IF;
    
    COMMIT;
  3. 锁管理:避免长时间持有锁

    sql
    -- 好的做法:尽快释放锁
    START TRANSACTION;
    SELECT * FROM accounts WHERE id = 1 FOR UPDATE;
    -- 快速处理
    UPDATE accounts SET balance = balance - 100 WHERE id = 1;
    COMMIT;
    
    -- 避免:长时间持有锁
    START TRANSACTION;
    SELECT * FROM accounts WHERE id = 1 FOR UPDATE;
    -- 复杂的业务逻辑处理
    -- 网络调用
    -- 用户交互
    UPDATE accounts SET balance = balance - 100 WHERE id = 1;
    COMMIT;
  4. 隔离级别选择:根据需要选择合适的隔离级别

    sql
    -- 对于报表查询,可以使用较低的隔离级别
    SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
    START TRANSACTION;
    SELECT COUNT(*), AVG(amount) FROM orders WHERE date >= '2024-01-01';
    COMMIT;
    
    -- 对于关键业务操作,使用较高的隔离级别
    SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
    START TRANSACTION;
    -- 关键的金融操作
    COMMIT;
  5. 死锁预防:避免死锁的发生

    sql
    -- 好的做法:按固定顺序访问资源
    START TRANSACTION;
    SELECT * FROM accounts WHERE id = LEAST(@id1, @id2) FOR UPDATE;
    SELECT * FROM accounts WHERE id = GREATEST(@id1, @id2) FOR UPDATE;
    -- 处理转账
    COMMIT;
    
    -- 避免:不同顺序访问资源
    -- 事务1:先锁定账户A,再锁定账户B
    -- 事务2:先锁定账户B,再锁定账户A
    -- 可能导致死锁

MySQL 语法特性 ​

1. 大小写敏感性 ​

MySQL 的大小写敏感性规则比较复杂,需要根据不同的对象类型和操作系统来判断。

关键字大小写 ​

sql
-- 以下写法都是等效的
SELECT * FROM users;
select * from users;
Select * From Users;
SeLeCt * FrOm UsErS;

数据库名和表名大小写 ​

sql
-- 在 Linux/Unix 系统上,以下是不同的数据库
CREATE DATABASE MyApp;
CREATE DATABASE myapp;
CREATE DATABASE MYAPP;

-- 在 Windows 系统上,以下被视为同一个数据库
CREATE DATABASE MyApp;  -- 会报错,因为 myapp 已存在
CREATE DATABASE myapp;

-- 查看系统变量
SHOW VARIABLES LIKE 'lower_case_table_names';
-- 0: 区分大小写(Linux/Unix 默认)
-- 1: 不区分大小写(Windows 默认)
-- 2: 存储时保持原样,比较时转为小写(macOS 默认)

列名大小写 ​

sql
-- 列名通常不区分大小写
CREATE TABLE users (
    ID int,
    UserName varchar(50),
    email VARCHAR(100)
);

-- 以下查询都是有效的
SELECT id, username, EMAIL FROM users;
SELECT ID, UserName, email FROM users;
SELECT Id, USERNAME, Email FROM users;

字符串值大小写 ​

sql
-- 字符串值默认区分大小写
SELECT * FROM users WHERE username = 'John';     -- 只匹配 'John'
SELECT * FROM users WHERE username = 'john';     -- 只匹配 'john'
SELECT * FROM users WHERE username = 'JOHN';     -- 只匹配 'JOHN'

-- 使用 COLLATE 进行不区分大小写的比较
SELECT * FROM users WHERE username COLLATE utf8mb4_general_ci = 'john';

-- 使用函数进行大小写转换
SELECT * FROM users WHERE LOWER(username) = LOWER('John');
SELECT * FROM users WHERE UPPER(username) = 'JOHN';

-- 创建表时指定排序规则
CREATE TABLE users (
    id INT PRIMARY KEY,
    username VARCHAR(50) COLLATE utf8mb4_general_ci,  -- 不区分大小写
    email VARCHAR(100) COLLATE utf8mb4_bin             -- 区分大小写
);

2. 标识符规则 ​

MySQL 标识符(数据库名、表名、列名等)有特定的命名规则和限制。

基本命名规则 ​

sql
-- 有效的标识符
CREATE TABLE user_profiles (          -- 下划线分隔
    user_id INT,
    first_name VARCHAR(50),
    last_name VARCHAR(50),
    created_at TIMESTAMP
);

CREATE TABLE UserProfiles (           -- 驼峰命名
    UserId INT,
    FirstName VARCHAR(50),
    LastName VARCHAR(50),
    CreatedAt TIMESTAMP
);

CREATE TABLE users2024 (              -- 包含数字
    id INT,
    name VARCHAR(50)
);

CREATE TABLE `order` (                -- 使用反引号包围保留字
    id INT,
    amount DECIMAL(10,2)
);

长度限制示例 ​

sql
-- 标识符最长 64 个字符
CREATE TABLE very_long_table_name_that_describes_user_activity_logs_2024 (
    id INT,
    activity_description TEXT
);

-- 超过 64 字符会报错
-- CREATE TABLE this_table_name_is_way_too_long_and_exceeds_the_maximum_allowed_length_limit (
--     id INT
-- );

特殊字符和保留字处理 ​

sql
-- 使用反引号处理特殊字符
CREATE TABLE `user-profiles` (        -- 包含连字符
    `user-id` INT,
    `first name` VARCHAR(50),         -- 包含空格
    `@email` VARCHAR(100)             -- 包含特殊字符
);

-- 保留字作为标识符
CREATE TABLE `select` (
    `from` INT,
    `where` VARCHAR(50),
    `order` TEXT
);

-- 查询时也需要使用反引号
SELECT `from`, `where` FROM `select` WHERE `order` = 'test';

-- 查看所有保留字
SHOW KEYWORDS;

标识符最佳实践 ​

sql
-- 推荐的命名风格
CREATE TABLE user_accounts (          -- 使用下划线分隔
    account_id INT PRIMARY KEY,       -- 主键明确标识
    user_name VARCHAR(50) NOT NULL,   -- 描述性名称
    email_address VARCHAR(100),       -- 完整描述
    created_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    is_active BOOLEAN DEFAULT TRUE    -- 布尔值使用 is_ 前缀
);

-- 避免的命名方式
CREATE TABLE t1 (                     -- 避免:无意义的名称
    c1 INT,                           -- 避免:无意义的列名
    `select` VARCHAR(50),             -- 避免:使用保留字
    `user name` VARCHAR(50)           -- 避免:包含空格
);

3. 注释语法 ​

MySQL 支持多种注释语法,用于代码文档化和临时禁用代码。

单行注释 ​

sql
-- 这是单行注释(标准 SQL 风格)
SELECT * FROM users; -- 查询所有用户

# 这也是单行注释(MySQL 特有风格)
SELECT * FROM products; # 查询所有产品

-- 注释可以用于解释复杂逻辑
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
-- 只统计最近一年的数据
WHERE o.created_at >= DATE_SUB(NOW(), INTERVAL 1 YEAR)
GROUP BY u.id, u.username;

多行注释 ​

sql
/*
这是多行注释
可以跨越多行
用于详细说明
*/
SELECT * FROM users;

/*
复杂查询说明:
1. 连接用户表和订单表
2. 计算每个用户的订单统计
3. 按消费金额排序
4. 只返回前10名用户
*/
SELECT 
    u.username,
    COUNT(o.id) as order_count,
    SUM(o.total_amount) as total_spent
FROM users u
INNER JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.username
ORDER BY total_spent DESC
LIMIT 10;

/* 临时禁用某些列
SELECT 
    username,
    email,
    -- phone,
    -- address
FROM users;
*/

MySQL 特有注释 ​

sql
/*! MySQL 特有语法注释 */
/*! 这些注释中的代码只在 MySQL 中执行 */

-- 版本特定注释
CREATE TABLE users (
    id INT PRIMARY KEY,
    username VARCHAR(50),
    /*! 50000 password VARCHAR(255) */,  -- MySQL 5.0.0+ 才执行
    /*! 80000 json_data JSON */          -- MySQL 8.0.0+ 才执行
);

-- 引擎特定注释
CREATE TABLE logs (
    id INT PRIMARY KEY,
    message TEXT,
    created_at TIMESTAMP
) /*! ENGINE=InnoDB */;  -- 指定存储引擎

-- 索引提示注释
SELECT /*! USE INDEX (idx_username) */ * 
FROM users 
WHERE username = 'john';

-- 优化器提示注释
SELECT /*+ USE_INDEX(users idx_email) */ *
FROM users 
WHERE email = 'john@example.com';

4. 字符串处理 ​

MySQL 提供了丰富的字符串处理功能,包括不同的引号类型、转义字符和字符集支持。

引号使用 ​

sql
-- 单引号和双引号都可以用于字符串
SELECT 'Hello World' as greeting1;
SELECT "Hello World" as greeting2;

-- 在字符串中包含引号
SELECT 'It\'s a beautiful day' as message1;        -- 转义单引号
SELECT "He said \"Hello\"" as message2;            -- 转义双引号
SELECT 'He said "Hello"' as message3;             -- 单引号中包含双引号
SELECT "It's a beautiful day" as message4;        -- 双引号中包含单引号

-- 使用 QUOTE 函数自动处理引号
SELECT QUOTE('It\'s a "test" string') as quoted_string;

转义字符 ​

sql
-- 常用转义字符
SELECT 'Line 1\nLine 2' as multiline;              -- \n 换行符
SELECT 'Column1\tColumn2' as tabbed;               -- \t 制表符
SELECT 'Path: C:\\Users\\John' as windows_path;     -- \\ 反斜杠
SELECT 'Quote: \'Hello\'' as quoted;               -- \' 单引号
SELECT "Quote: \"Hello\"" as double_quoted;        -- \" 双引号
SELECT 'Backspace: \b' as backspace;               -- \b 退格符
SELECT 'Carriage Return: \r' as carriage_return;   -- \r 回车符

-- 使用十六进制和八进制
SELECT '\x41\x42\x43' as hex_abc;                  -- 十六进制 ABC
SELECT '\101\102\103' as octal_abc;                -- 八进制 ABC

-- Unicode 字符
SELECT '\u4E2D\u6587' as chinese;                  -- Unicode 中文

字符集和排序规则 ​

sql
-- 查看支持的字符集
SHOW CHARACTER SET;
SHOW CHARACTER SET LIKE 'utf8%';

-- 查看排序规则
SHOW COLLATION;
SHOW COLLATION WHERE Charset = 'utf8mb4';

-- 设置字符集和排序规则
CREATE DATABASE myapp 
CHARACTER SET utf8mb4 
COLLATE utf8mb4_unicode_ci;

CREATE TABLE users (
    id INT PRIMARY KEY,
    username VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci,
    email VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin,
    description TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
);

-- 在查询中指定排序规则
SELECT * FROM users 
WHERE username COLLATE utf8mb4_general_ci = 'John';

-- 转换字符集
SELECT CONVERT('Hello' USING utf8mb4) as converted;
SELECT CAST('Hello' AS CHAR CHARACTER SET utf8mb4) as casted;

字符串函数示例 ​

sql
-- 字符串长度和字节长度
SELECT 
    CHAR_LENGTH('Hello 世界') as char_len,    -- 字符长度:8
    LENGTH('Hello 世界') as byte_len;         -- 字节长度:11(UTF-8)

-- 字符串连接
SELECT 
    CONCAT('Hello', ' ', 'World') as concat1,
    CONCAT_WS(' ', 'Hello', 'Beautiful', 'World') as concat2;

-- 字符串截取
SELECT 
    LEFT('Hello World', 5) as left_part,      -- 'Hello'
    RIGHT('Hello World', 5) as right_part,    -- 'World'
    SUBSTRING('Hello World', 7, 5) as mid_part, -- 'World'
    SUBSTRING('Hello World', 7) as from_pos;   -- 'World'

-- 字符串查找和替换
SELECT 
    LOCATE('World', 'Hello World') as position,  -- 7
    REPLACE('Hello World', 'World', 'MySQL') as replaced,
    INSERT('Hello World', 7, 5, 'MySQL') as inserted;

-- 大小写转换
SELECT 
    UPPER('Hello World') as uppercase,
    LOWER('Hello World') as lowercase,
    INITCAP('hello world') as title_case;  -- MySQL 8.0+

-- 字符串修剪
SELECT 
    TRIM('  Hello World  ') as trimmed,
    LTRIM('  Hello World  ') as left_trimmed,
    RTRIM('  Hello World  ') as right_trimmed,
    TRIM('x' FROM 'xxxHello Worldxxx') as custom_trimmed;

-- 字符串填充
SELECT 
    LPAD('123', 6, '0') as left_padded,    -- '000123'
    RPAD('123', 6, '0') as right_padded;   -- '123000'

5. 数值和日期处理 ​

数值处理 ​

sql
-- 数值格式化
SELECT 
    FORMAT(1234567.89, 2) as formatted,        -- '1,234,567.89'
    FORMAT(1234567.89, 0) as no_decimal;       -- '1,234,568'

-- 数值函数
SELECT 
    ROUND(123.456, 2) as rounded,              -- 123.46
    CEIL(123.456) as ceiling,                  -- 124
    FLOOR(123.456) as floor,                   -- 123
    TRUNCATE(123.456, 1) as truncated;         -- 123.4

-- 数学函数
SELECT 
    ABS(-123) as absolute,                     -- 123
    POWER(2, 3) as power,                      -- 8
    SQRT(16) as square_root,                   -- 4
    MOD(10, 3) as modulo;                      -- 1

日期时间处理 ​

sql
-- 当前日期时间
SELECT 
    NOW() as current_datetime,
    CURDATE() as current_date,
    CURTIME() as current_time,
    UNIX_TIMESTAMP() as unix_timestamp;

-- 日期格式化
SELECT 
    DATE_FORMAT(NOW(), '%Y-%m-%d') as date_only,
    DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s') as datetime,
    DATE_FORMAT(NOW(), '%W, %M %D, %Y') as readable_date;

-- 日期计算
SELECT 
    DATE_ADD(NOW(), INTERVAL 1 DAY) as tomorrow,
    DATE_SUB(NOW(), INTERVAL 1 WEEK) as last_week,
    DATEDIFF('2024-12-31', NOW()) as days_to_new_year;

-- 日期提取
SELECT 
    YEAR(NOW()) as current_year,
    MONTH(NOW()) as current_month,
    DAY(NOW()) as current_day,
    DAYOFWEEK(NOW()) as day_of_week,
    WEEKDAY(NOW()) as weekday;

最佳实践建议 ​

1. 代码风格 ​

  • 关键字大写:虽然不强制,但建议关键字使用大写
  • 缩进对齐:使用适当的缩进提高可读性
  • 换行规则:复杂查询适当换行
  • 别名使用:为表和列使用有意义的别名

2. 性能考虑 ​

  • 索引利用:编写能够有效利用索引的查询
  • 避免全表扫描:使用适当的 WHERE 条件
  • 限制结果集:使用 LIMIT 限制返回数据量
  • 子查询优化:考虑将子查询改写为连接查询

3. 安全性 ​

  • 参数化查询:避免 SQL 注入攻击
  • 权限最小化:只授予必要的权限
  • 敏感数据保护:对敏感数据进行加密
  • 审计日志:启用适当的审计功能

4. 可维护性 ​

  • 文档化:为复杂查询添加注释
  • 模块化:将复杂逻辑分解为多个步骤
  • 版本控制:对数据库结构变更进行版本管理
  • 测试验证:在生产环境前充分测试

学习建议 ​

初学者阶段 ​

  1. 从简单的 SELECT 查询开始
  2. 逐步学习 WHERE 条件的使用
  3. 掌握基本的 INSERT、UPDATE、DELETE 操作
  4. 理解表的创建和基本约束

进阶阶段 ​

  1. 深入学习连接查询
  2. 掌握聚合函数和分组查询
  3. 学习子查询和复杂查询
  4. 理解索引对查询性能的影响

高级阶段 ​

  1. 学习查询优化技巧
  2. 掌握存储过程和函数
  3. 理解事务和锁机制
  4. 学习数据库设计原则

MySQL 基础语法是数据库操作的基础,掌握这些概念和原理对于后续的深入学习至关重要。建议通过大量的实践来加深理解,同时关注性能和安全性方面的最佳实践。

别急,先让缓存热一下。