SQL 语法面试考点

一、SQL 基础与 DDL

1. 数据库操作

复制代码
-- 创建数据库
CREATE DATABASE dbname
CHARACTER SET utf8mb4
COLLATE utf8mb4_general_ci;

-- 删除数据库
DROP DATABASE IF EXISTS dbname;

-- 选择数据库
USE dbname;

2. 表操作

复制代码
-- 创建表
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL UNIQUE,
    email VARCHAR(100) UNIQUE,
    age INT CHECK (age >= 0),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 修改表结构
ALTER TABLE users 
ADD COLUMN phone VARCHAR(20) AFTER email,
MODIFY COLUMN username VARCHAR(100) NOT NULL,
DROP COLUMN old_column,
ADD INDEX idx_email (email);

-- 删除表
DROP TABLE IF EXISTS users;

-- 清空表(不可回滚)
TRUNCATE TABLE users;

二、DML 数据操作

1. 增删改查 CRUD

复制代码
-- INSERT
INSERT INTO users (username, email, age) 
VALUES 
('john', 'john@example.com', 25),
('jane', 'jane@example.com', 30);

-- 插入查询结果
INSERT INTO user_backup SELECT * FROM users WHERE age > 20;

-- UPDATE
UPDATE users 
SET age = age + 1, updated_at = NOW()
WHERE id = 1;

-- 多表更新
UPDATE users u
JOIN orders o ON u.id = o.user_id
SET u.order_count = u.order_count + 1
WHERE o.status = 'completed';

-- DELETE
DELETE FROM users WHERE age < 18;
DELETE u FROM users u WHERE NOT EXISTS (
    SELECT 1 FROM orders o WHERE o.user_id = u.id
);

三、SELECT 查询核心

先执行FROM 子句,确定要查询的数据来源;接着执行WHERE 子句,筛选出符合条件的记录;然后执行GROUP BY 子句,对筛选后的数据进行分组;再执行HAVING 子句,对分组后的数据进行筛选;之后执行SELECT 子句,选择要查询的列;最后执行ORDER BY子句,对查询结果进行排序。

having只能跟在group by后面

1. 基础查询

复制代码
-- 基本结构
SELECT DISTINCT column1, column2, ...
FROM table_name
WHERE conditions
GROUP BY columns
HAVING group_conditions
ORDER BY columns
LIMIT n OFFSET m;

ASC ​ - 升序(默认 ,从小到大,A 到 Z)。DESC​ - 降序(从大到小,Z 到 A)

语法

复制代码
SELECT 列1, 列2
FROM 表名
ORDER BY 列1 DESC;  -- 按列1降序排列

LIMIT {要返回的记录数} OFFSET {要跳过的记录数}

或简化写法:

LIMIT {跳过的记录数}, {要返回的记录数}

详细说明

语法1:使用 OFFSET 关键字

SELECT * FROM 表名

LIMIT 5 OFFSET 10;

解释:跳过前 10 条记录,返回接下来的 5 条记录。

2. WHERE 条件

复制代码
-- 比较运算符
SELECT * FROM products WHERE price > 100;
SELECT * FROM users WHERE age BETWEEN 18 AND 60;
SELECT * FROM users WHERE name IN ('John', 'Jane');

-- 模糊查询
SELECT * FROM products WHERE name LIKE 'apple%';  -- 以apple开头
SELECT * FROM products WHERE name LIKE '%phone%'; -- 包含phone
SELECT * FROM products WHERE name LIKE 'c_mputer';-- 单个字符匹配

-- NULL处理
SELECT * FROM users WHERE email IS NULL;
SELECT * FROM users WHERE email IS NOT NULL;

3. 聚合函数

复制代码
-- 常用聚合函数
SELECT 
    COUNT(*) as total_rows,
    COUNT(DISTINCT user_id) as unique_users,
    SUM(amount) as total_amount,
    AVG(price) as average_price,
    MAX(price) as max_price,
    MIN(price) as min_price
FROM orders;

聚合函数是对分组后的数据进行计算

聚合函数不能直接用在where子句里。因为WHERE子句执行的时候,还没进行分组和聚合操作

四、JOIN 连接查询

1. 连接类型对比

from 表1 join 表2 on 条件

复制代码
-- INNER JOIN(内连接)
SELECT u.name, o.order_no
FROM users u
INNER JOIN orders o ON u.id = o.user_id;

-- LEFT JOIN(左外连接)
SELECT u.name, o.order_no
FROM users u
LEFT JOIN orders o ON u.id = o.user_id;

-- RIGHT JOIN(右外连接)
SELECT u.name, o.order_no
FROM users u
RIGHT JOIN orders o ON u.id = o.user_id;

-- FULL OUTER JOIN(全外连接)- MySQL不支持
-- 通过UNION模拟
SELECT u.name, o.order_no FROM users u LEFT JOIN orders o ON u.id = o.user_id
UNION
SELECT u.name, o.order_no FROM users u RIGHT JOIN orders o ON u.id = o.user_id;

-- CROSS JOIN(交叉连接)
SELECT * FROM colors CROSS JOIN sizes;

2. 自连接

复制代码
-- 查询每个员工的经理
SELECT e.name as employee, m.name as manager
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.id;

五、子查询

1. 标量子查询

复制代码
-- 返回单个值
SELECT name, (SELECT AVG(price) FROM products) as avg_price
FROM products;

SELECT * FROM products 
WHERE price > (SELECT AVG(price) FROM products);

2. 行子查询

复制代码
SELECT * FROM users
WHERE (age, salary) = (
    SELECT MIN(age), MAX(salary) 
    FROM users
);

3. 列子查询

复制代码
-- IN子查询
SELECT * FROM products
WHERE category_id IN (
    SELECT id FROM categories WHERE status = 'active'
);

-- ANY/SOME子查询
SELECT * FROM products
WHERE price > ANY (
    SELECT price FROM products WHERE category = 'premium'
);

-- ALL子查询
SELECT * FROM products
WHERE price > ALL (
    SELECT price FROM products WHERE category = 'basic'
);

4. 表子查询

复制代码
-- FROM子句中的子查询
SELECT * FROM (
    SELECT user_id, COUNT(*) as order_count
    FROM orders
    GROUP BY user_id
) t WHERE order_count > 5;

六、窗口函数(MySQL 8.0+)

1. 排名函数

复制代码
-- ROW_NUMBER() 连续排名
SELECT 
    name, salary,
    ROW_NUMBER() OVER (ORDER BY salary DESC) as rank
FROM employees;

-- RANK() 并列有间隔
SELECT 
    name, salary,
    RANK() OVER (ORDER BY salary DESC) as rank
FROM employees;

-- DENSE_RANK() 并列无间隔
SELECT 
    name, salary,
    DENSE_RANK() OVER (ORDER BY salary DESC) as rank
FROM employees;

2. 分布函数

复制代码
-- NTILE(n) 分组
SELECT 
    name, salary,
    NTILE(4) OVER (ORDER BY salary DESC) as quartile
FROM employees;

3. 前后值函数

复制代码
SELECT 
    date, revenue,
    LAG(revenue, 1) OVER (ORDER BY date) as prev_revenue,
    LEAD(revenue, 1) OVER (ORDER BY date) as next_revenue
FROM daily_sales;

4. 聚合窗口函数

复制代码
SELECT 
    department, name, salary,
    SUM(salary) OVER (PARTITION BY department) as dept_total,
    AVG(salary) OVER (PARTITION BY department) as dept_avg,
    salary * 100.0 / SUM(salary) OVER (PARTITION BY department) as percentage
FROM employees;

七、高级查询技巧

1. CASE表达式

复制代码
SELECT 
    name,
    age,
    CASE 
        WHEN age < 18 THEN '未成年'
        WHEN age BETWEEN 18 AND 60 THEN '成年'
        ELSE '老年'
    END as age_group,
    CASE status
        WHEN 1 THEN '激活'
        WHEN 0 THEN '禁用'
        ELSE '未知'
    END as status_desc
FROM users;

2. 分组筛选

复制代码
-- 分组后筛选
SELECT department, COUNT(*) as emp_count
FROM employees
GROUP BY department
HAVING COUNT(*) > 5;  -- HAVING 在分组后过滤

-- WHERE 在分组前过滤
SELECT department, AVG(salary) as avg_salary
FROM employees
WHERE hire_date > '2020-01-01'
GROUP BY department;

3. 分页查询优化

复制代码
-- 传统分页(大数据量慢)
SELECT * FROM orders ORDER BY id LIMIT 10000, 20;

-- 优化分页(使用索引)
SELECT * FROM orders 
WHERE id > 10000  -- 记住上次的最大ID
ORDER BY id LIMIT 20;

-- 子查询优化
SELECT * FROM orders 
WHERE id >= (SELECT id FROM orders ORDER BY id LIMIT 10000, 1)
ORDER BY id LIMIT 20;

八、索引优化

1. 索引类型

复制代码
-- 创建索引
CREATE INDEX idx_name ON users(name);
CREATE UNIQUE INDEX idx_email ON users(email);
CREATE INDEX idx_name_age ON users(name, age);  -- 复合索引
CREATE FULLTEXT INDEX idx_content ON articles(content);  -- 全文索引

-- 删除索引
DROP INDEX idx_name ON users;

2. 最左前缀原则

复制代码
-- 假设有复合索引 (a, b, c)
-- 有效使用索引:
SELECT * FROM t WHERE a = 1;
SELECT * FROM t WHERE a = 1 AND b = 2;
SELECT * FROM t WHERE a = 1 AND b = 2 AND c = 3;
SELECT * FROM t WHERE a = 1 AND c = 3;  -- 只用到了a

-- 无效使用索引:
SELECT * FROM t WHERE b = 2;  -- 无法使用索引
SELECT * FROM t WHERE b = 2 AND c = 3;  -- 无法使用索引

九、事务控制

1. ACID 特性

复制代码
-- 开启事务
START TRANSACTION;
-- 或
BEGIN;

-- 事务操作
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;

-- 提交或回滚
COMMIT;  -- 提交事务
ROLLBACK;  -- 回滚事务

-- 设置保存点
SAVEPOINT sp1;
-- 回滚到保存点
ROLLBACK TO SAVEPOINT sp1;

2. 事务隔离级别

复制代码
-- 查看当前隔离级别
SELECT @@transaction_isolation;

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

十、视图与存储过程

1. 视图

复制代码
-- 创建视图
CREATE VIEW user_orders AS
SELECT u.id, 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, u.name;

-- 使用视图
SELECT * FROM user_orders WHERE order_count > 5;

-- 修改视图
CREATE OR REPLACE VIEW user_orders AS ...;

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

2. 存储过程

复制代码
DELIMITER //

CREATE PROCEDURE get_user_orders(IN user_id INT)
BEGIN
    SELECT * FROM orders 
    WHERE user_id = user_id
    ORDER BY created_at DESC;
END //

DELIMITER ;

-- 调用存储过程
CALL get_user_orders(123);

十一、SQL 优化考点

1. EXPLAIN 分析

复制代码
EXPLAIN SELECT * FROM users WHERE age > 20;
字段 说明 优化目标
type 访问类型 至少range,最好const/ref
key 使用的索引 必须使用索引
rows 预估扫描行数 越少越好
Extra 额外信息 避免Using filesort/temporary

2. 优化技巧

复制代码
-- 1. 避免 SELECT *
SELECT id, name FROM users;  -- 只选择需要的列

-- 2. 使用 LIMIT
SELECT * FROM users LIMIT 100;

-- 3. 避免在WHERE中对字段做计算
SELECT * FROM users WHERE YEAR(created_at) = 2024;  -- ❌
SELECT * FROM users WHERE created_at >= '2024-01-01';  -- ✅

-- 4. 避免使用OR
SELECT * FROM users WHERE age = 20 OR age = 30;  -- ❌
SELECT * FROM users WHERE age IN (20, 30);  -- ✅

-- 5. 使用EXISTS代替IN
SELECT * FROM users 
WHERE EXISTS (SELECT 1 FROM orders WHERE orders.user_id = users.id);

十二、常见面试题

1. 排名问题

复制代码
-- 查询每个部门工资前三高的员工
SELECT * FROM (
    SELECT 
        department, name, salary,
        DENSE_RANK() OVER (PARTITION BY department ORDER BY salary DESC) as rank
    FROM employees
) t WHERE rank <= 3;

2. 连续登录问题

复制代码
-- 查询连续登录7天的用户
SELECT user_id
FROM (
    SELECT 
        user_id,
        login_date,
        DATE_SUB(login_date, INTERVAL ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_date) DAY) as diff
    FROM login_logs
) t
GROUP BY user_id, diff
HAVING COUNT(*) >= 7;

3. 行转列/列转行

复制代码
-- 行转列(PIVOT)
SELECT 
    student_id,
    MAX(CASE WHEN subject = 'Math' THEN score END) as Math,
    MAX(CASE WHEN subject = 'English' THEN score END) as English
FROM scores
GROUP BY student_id;

-- 列转行(UNPIVOT)
SELECT student_id, 'Math' as subject, Math as score FROM scores
UNION ALL
SELECT student_id, 'English' as subject, English as score FROM scores;

4. 删除重复数据

复制代码
-- 保留id最小的重复数据
DELETE FROM users
WHERE id NOT IN (
    SELECT MIN(id)
    FROM users
    GROUP BY email
    HAVING COUNT(*) > 1
);

十三、SQL 注入防护

1. 预编译语句

复制代码
-- Java中使用PreparedStatement
String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setString(1, username);
pstmt.setString(2, password);

2. 输入验证

复制代码
// 对输入进行验证
if (!username.matches("^[a-zA-Z0-9_]{3,20}$")) {
    throw new IllegalArgumentException("Invalid username");
}

面试准备要点

  1. 熟练掌握JOIN的各种用法和区别

  2. 深入理解子查询和连接的性能差异

  3. 掌握窗口函数的应用场景

  4. 熟悉EXPLAIN分析SQL执行计划

  5. 了解索引优化原则

  6. 准备实际优化案例

  7. 熟悉事务和锁机制

  8. 了解SQL注入防护

高频考点

  • 多表JOIN查询

  • 子查询 vs JOIN性能

  • 分组聚合和HAVING

  • 窗口函数应用

  • 索引优化策略

  • 事务隔离级别

  • 慢SQL优化

  • 分页查询优化

相关推荐
xuxie992 小时前
Next 13 sqlite3 查找、网页
java·数据库·oracle
V1ncent Chen2 小时前
从零学SQL 04 MySQL Workbench用法简介
数据库·sql·mysql·数据分析
洛克大航海2 小时前
SQLite 的安装
数据库·sqlite
ZZZKKKRTSAE2 小时前
在rhel9中部署MySQL
数据库·mysql
杨云龙UP2 小时前
Oracle与MySQL数据库运行状态快速检查指南
数据库·mysql·oracle
rrrjqy2 小时前
MySQL事务深度解析:从ACID特性到隔离级别实战
数据库·mysql·oracle
Saniffer_SH2 小时前
【高清视频】企业级NVMe SSD (E3.S, U.2)和消费类M.2 SSD拆解分析
服务器·网络·数据库·驱动开发·测试工具·fpga开发·压力测试
顶点多余2 小时前
Mysql数据库基础
linux·数据库·mysql
小吴编程之路2 小时前
MySQL 事务管理核心解析:从 ACID 到 MVCC 深度理解
数据库·mysql