Appearance
SQL基础面试题
1. SQL的基本概念
问题:什么是SQL?SQL有哪些分类?
答案:
- SQL(Structured Query Language):结构化查询语言,用于管理关系型数据库。
- 分类:
- DDL(Data Definition Language):数据定义语言,如CREATE、ALTER、DROP。
- DML(Data Manipulation Language):数据操作语言,如INSERT、UPDATE、DELETE。
- DQL(Data Query Language):数据查询语言,如SELECT。
- DCL(Data Control Language):数据控制语言,如GRANT、REVOKE。
- TCL(Transaction Control Language):事务控制语言,如COMMIT、ROLLBACK。
2. SELECT语句
问题:SELECT语句的基本语法是什么?
答案:
sql
SELECT column1, column2, ...
FROM table_name
WHERE condition
GROUP BY column1, column2, ...
HAVING condition
ORDER BY column1, column2, ...
LIMIT offset, count;3. WHERE子句
问题:WHERE子句中常用的运算符有哪些?
答案:
- 比较运算符:=、!=、<>、>、<、>=、<=
- 逻辑运算符:AND、OR、NOT
- 范围运算符:BETWEEN、IN、NOT IN
- 模糊匹配:LIKE、NOT LIKE
- 空值判断:IS NULL、IS NOT NULL
4. LIKE运算符
问题:LIKE运算符中常用的通配符有哪些?
答案:
- %:匹配任意多个字符。
- _:匹配单个字符。
示例:
sql
-- 查询名字以J开头的用户
SELECT * FROM users WHERE name LIKE 'J%';
-- 查询名字包含oh的用户
SELECT * FROM users WHERE name LIKE '%oh%';
-- 查询名字第二个字符为o的用户
SELECT * FROM users WHERE name LIKE '_o%';5. GROUP BY和HAVING
问题:GROUP BY和HAVING有什么区别?
答案:
- GROUP BY:根据一个或多个列对结果集进行分组。
- HAVING:对分组后的结果集进行过滤。
示例:
sql
-- 查询每个部门的平均工资
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department;
-- 查询平均工资大于5000的部门
SELECT department, AVG(salary) AS avg_salary
FROM employees
GROUP BY department
HAVING AVG(salary) > 5000;6. JOIN
问题:SQL中有哪些类型的JOIN?
答案:
- INNER JOIN:内连接,只返回两个表中匹配的行。
- LEFT JOIN:左连接,返回左表的所有行,右表匹配的行,不匹配的用NULL填充。
- RIGHT JOIN:右连接,返回右表的所有行,左表匹配的行,不匹配的用NULL填充。
- FULL JOIN:全连接,返回两个表的所有行,不匹配的用NULL填充。
- CROSS JOIN:交叉连接,返回两个表的笛卡尔积。
示例:
sql
-- 内连接
SELECT * FROM orders
INNER JOIN customers ON orders.customer_id = customers.id;
-- 左连接
SELECT * FROM orders
LEFT JOIN customers ON orders.customer_id = customers.id;
-- 右连接
SELECT * FROM orders
RIGHT JOIN customers ON orders.customer_id = customers.id;
-- 全连接
SELECT * FROM orders
FULL JOIN customers ON orders.customer_id = customers.id;7. 子查询
问题:什么是子查询?子查询有哪些类型?
答案:
- 子查询:嵌套在另一个查询中的查询。
- 类型:
- 标量子查询:返回单个值的子查询。
- 列子查询:返回单列的子查询。
- 行子查询:返回单行的子查询。
- 表子查询:返回多行多列的子查询。
示例:
sql
-- 标量子查询
SELECT * FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);
-- 列子查询
SELECT * FROM employees
WHERE department_id IN (SELECT id FROM departments WHERE name = 'IT');
-- 表子查询
SELECT * FROM (SELECT * FROM employees WHERE salary > 5000) AS high_salary_employees;8. 聚合函数
问题:SQL中有哪些常用的聚聚合函数?
答案:
- COUNT:计算行数。
- SUM:计算总和。
- AVG:计算平均值。
- MAX:计算最大值。
- MIN:计算最小值。
示例:
sql
-- 计算员工总数
SELECT COUNT(*) FROM employees;
-- 计算工资总和
SELECT SUM(salary) FROM employees;
-- 计算平均工资
SELECT AVG(salary) FROM employees;
-- 计算最高工资
SELECT MAX(salary) FROM employees;
-- 计算最低工资
SELECT MIN(salary) FROM employees;9. DISTINCT
问题:DISTINCT有什么作用?
答案:
- DISTINCT:用于去除结果集中的重复行。
示例:
sql
-- 查询所有不重复的部门
SELECT DISTINCT department FROM employees;
-- 查询所有不重复的部门和职位组合
SELECT DISTINCT department, position FROM employees;10. UNION
问题:UNION和UNION ALL有什么区别?
答案:
- UNION:合并两个查询的结果集,去除重复行。
- UNION ALL:合并两个查询的结果集,保留重复行。
示例:
sql
-- UNION
SELECT name FROM employees
UNION
SELECT name FROM customers;
-- UNION ALL
SELECT name FROM employees
UNION ALL
SELECT name FROM customers;11. 事务
问题:什么是事务?事务的ACID特性是什么?
答案:
- 事务:一组数据库操作,要么全部成功,要么全部失败。
- ACID特性:
- 原子性(Atomicity):事务是不可分割的工作单位,要么全部成功,要么全部失败。
- 一致性(Consistency):事务执行前后,数据库从一个一致性状态变换到另一个一致性状态。
- 隔离性(Isolation):事务的执行不受其他事务的干扰。
- 持久性(Durability):事务一旦提交,对数据库的修改是永久的。
12. 事务隔离级别
问题:事务有哪些隔离级别?
答案:
- READ UNCOMMITTED:读取未提交的数据,可能导致脏读、不可重复读、幻读。
- READ COMMITTED:读取已提交的数据,可能导致不可重复读、幻读。
- REPEATABLE READ:可重复读,可能导致幻读。
- SERIALIZABLE:串行化,最严格的隔离级别,避免所有并发问题。
13. 索引
问题:什么是索引?索引有什么作用?
答案:
- 索引:数据库中用于提高查询速度的数据结构。
- 作用:
- 提高查询速度。
- 减少IO操作。
- 提高排序和分组效率。
示例:
sql
-- 创建索引
CREATE INDEX idx_name ON employees(name);
-- 创建复合索引
CREATE INDEX idx_name_age ON employees(name, age);
-- 删除索引
DROP INDEX idx_name ON employees;14. 视图
问题:什么是视图?视图有什么作用?
答案:
- 视图:虚拟表,基于一个或多个表的查询结果。
- 作用:
- 简化复杂查询。
- 保护敏感数据。
- 提供数据独立性。
示例:
sql
-- 创建视图
CREATE VIEW employee_view AS
SELECT id, name, department, salary
FROM employees
WHERE salary > 5000;
-- 使用视图
SELECT * FROM employee_view;
-- 删除视图
DROP VIEW employee_view;15. 存储过程
问题:什么是存储过程?如何创建存储过程?
答案:
- 存储过程:预编译的SQL语句集合,存储在数据库中。
- 作用:
- 提高性能。
- 减少网络传输。
- 提高安全性。
示例:
sql
-- 创建存储过程
CREATE PROCEDURE get_employees_by_department(IN dept_name VARCHAR(50))
BEGIN
SELECT * FROM employees WHERE department = dept_name;
END;
-- 调用存储过程
CALL get_employees_by_department('IT');
-- 删除存储过程
DROP PROCEDURE get_employees_by_department;16. 触发器
问题:什么是触发器?如何创建触发器?
答案:
- 触发器:在特定事件发生时自动执行的SQL语句。
- 作用:
- 自动维护数据一致性。
- 实现复杂的业务逻辑。
- 记录数据变更。
示例:
sql
-- 创建触发器
CREATE TRIGGER before_employee_insert
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
SET NEW.create_time = NOW();
END;
-- 删除触发器
DROP TRIGGER before_employee_insert;17. 约束
问题:SQL中有哪些约束?
答案:
- PRIMARY KEY:主键约束,唯一标识表中的每一行。
- FOREIGN KEY:外键约束,确保引用完整性。
- UNIQUE:唯一约束,确保列中的值唯一。
- NOT NULL:非空约束,确保列中的值不为空。
- CHECK:检查约束,确保列中的值满足指定条件。
- DEFAULT:默认值约束,为列指定默认值。
示例:
sql
-- 创建表时添加约束
CREATE TABLE employees (
id INT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
age INT CHECK (age >= 18),
department_id INT,
FOREIGN KEY (department_id) REFERENCES departments(id)
);
-- 添加约束
ALTER TABLE employees ADD UNIQUE(email);
-- 删除约束
ALTER TABLE employees DROP FOREIGN KEY fk_department;18. 分页查询
问题:如何实现分页查询?
答案:
sql
-- MySQL分页
SELECT * FROM employees
LIMIT 10 OFFSET 0;
-- Oracle分页
SELECT * FROM (
SELECT a.*, ROWNUM rn FROM (
SELECT * FROM employees
) a WHERE ROWNUM <= 10
) WHERE rn > 0;
-- SQL Server分页
SELECT * FROM employees
ORDER BY id
OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY;19. 窗口函数
问题:什么是窗口函数?常用的窗口函数有哪些?
答案:
- 窗口函数:在不改变行数的情况下,对结果集进行计算的函数。
- 常用窗口函数:
- ROW_NUMBER:为每行分配一个唯一的序号。
- RANK:为每行分配一个排名,相同值的行排名相同。
- DENSE_RANK:为每行分配一个排名,相同值的行排名相同,排名连续。
- LAG:获取当前行之前某行的值。
- LEAD:获取当前行之后某行的值。
- SUM、AVG、MAX、MIN:在窗口内计算聚合值。
示例:
sql
-- ROW_NUMBER
SELECT name, salary,
ROW_NUMBER() OVER (ORDER BY salary DESC) AS rank
FROM employees;
-- LAG
SELECT name, salary,
LAG(salary, 1) OVER (ORDER BY id) AS prev_salary
FROM employees;
-- SUM
SELECT name, salary,
SUM(salary) OVER (ORDER BY id) AS total_salary
FROM employees;20. CTE
问题:什么是CTE(Common Table Expression)?如何使用?
答案:
- CTE:公共表表达式,用于创建临时结果集。
- 作用:
- 提高查询的可读性。
- 简化复杂查询。
- 支持递归查询。
示例:
sql
-- CTE
WITH employee_cte AS (
SELECT id, name, salary
FROM employees
WHERE salary > 5000
)
SELECT * FROM employee_cte;
-- 递归CTE
WITH RECURSIVE employee_tree AS (
SELECT id, name, manager_id, 1 AS level
FROM employees
WHERE manager_id IS NULL
UNION ALL
SELECT e.id, e.name, e.manager_id, et.level + 1
FROM employees e
JOIN employee_tree et ON e.manager_id = et.id
)
SELECT * FROM employee_tree;21. 数据类型
问题:SQL中有哪些常用的数据类型?
答案:
- 数值类型:INT、BIGINT、FLOAT、DOUBLE、DECIMAL等。
- 字符串类型:CHAR、VARCHAR、TEXT等。
- 日期时间类型:DATE、TIME、DATETIME、TIMESTAMP等。
- 布尔类型:BOOLEAN、BIT等。
- 二进制类型:BINARY、VARBINARY、BLOB等。
22. NULL值
问题:NULL值有什么特点?如何处理NULL值?
答案:
- NULL值:表示未知或缺失的值。
- 特点:
- NULL不等于任何值,包括NULL本身。
- NULL参与运算,结果为NULL。
- 处理方式:
- 使用IS NULL或IS NOT NULL判断NULL值。
- 使用COALESCE函数将NULL值替换为默认值。
- 使用IFNULL函数(MySQL)或ISNULL函数(SQL Server)。
示例:
sql
-- 判断NULL值
SELECT * FROM employees WHERE name IS NULL;
-- 替换NULL值
SELECT COALESCE(name, 'Unknown') AS name FROM employees;
-- IFNULL函数(MySQL)
SELECT IFNULL(name, 'Unknown') AS name FROM employees;23. 日期函数
问题:SQL中有哪些常用的日期函数?
答案:
- NOW():获取当前日期和时间。
- CURDATE():获取当前日期。
- CURTIME():获取当前时间。
- DATE_ADD():日期加法。
- DATE_SUB():日期减法。
- DATEDIFF():计算日期差。
- DATE_FORMAT():格式化日期。
示例:
sql
-- 获取当前日期和时间
SELECT NOW();
-- 日期加法
SELECT DATE_ADD(NOW(), INTERVAL 1 DAY);
-- 计算日期差
SELECT DATEDIFF('2025-01-01', '2024-01-01');
-- 格式化日期
SELECT DATE_FORMAT(NOW(), '%Y-%m-%d %H:%i:%s');24. 字符串函数
问题:SQL中有哪些常用的字符串函数?
答案:
- CONCAT():连接字符串。
- SUBSTRING():截取字符串。
- LENGTH():获取字符串长度。
- UPPER():转换为大写。
- LOWER():转换为小写。
- TRIM():去除字符串两端的空格。
- REPLACE():替换字符串。
示例:
sql
-- 连接字符串
SELECT CONCAT('Hello', ' ', 'World');
-- 截取字符串
SELECT SUBSTRING('Hello, World!', 1, 5);
-- 获取字符串长度
SELECT LENGTH('Hello, World!');
-- 转换为大写
SELECT UPPER('hello');
-- 转换为小写
SELECT LOWER('HELLO');
-- 去除空格
SELECT TRIM(' Hello ');
-- 替换字符串
SELECT REPLACE('Hello, World!', 'World', 'Java');25. SQL优化
问题:如何优化SQL查询?
答案:
- 使用索引:为经常查询的列创建索引。
- **避免SELECT ***:只查询需要的列。
- 使用EXPLAIN:分析查询执行计划。
- 避免子查询:使用JOIN代替子查询。
- 使用LIMIT:限制返回的行数。
- 避免使用OR:使用IN代替OR。
- 使用EXISTS代替IN:EXISTS通常比IN快。
- 避免使用LIKE '%xxx%':使用全文索引。
- 使用UNION ALL代替UNION:如果不需要去重。
- 使用批量插入:减少INSERT语句的次数。
