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优化

  • 分页查询优化

相关推荐
hero.fei几秒前
排查redis出现报错ERR redis temporary failure
数据库·redis·缓存
野犬寒鸦9 分钟前
MySQL复习记录Day01
数据库·后端
ward RINL14 分钟前
Spring boot启动原理及相关组件
数据库·spring boot·后端
RisunJan22 分钟前
Linux命令-mysqldump(MySQL数据库中备份工具)
linux·数据库·mysql
DolphinDB智臾科技27 分钟前
直播回顾 | 物联网时序数据库如何驱动电力场景智能调度?
数据库·物联网·时序数据库
FinTech老王30 分钟前
告别“sql_mode“噩梦:MySQL 8.0 vs 5.7兼容性全对比与升级避坑指南
android·sql·mysql
郝学胜-神的一滴31 分钟前
解锁CS数据存储的核心逻辑:从结构选择到表单设计的全解析
linux·服务器·数据库·c++·后端·oracle
qq_3911053432 分钟前
TDengine C# 连接示例和授权管理
大数据·数据库·c#·时序数据库·tdengine
孟章豪34 分钟前
如何优雅封装.NET数据库访问层(彻底告别拼接SQL)
数据库·sql·.net
geBR OTTE37 分钟前
Spring Boot中集成MyBatis操作数据库详细教程
数据库·spring boot·mybatis