随着技术的发展和数据量的增加,对SQL的掌握变得越来越重要。在现代面试中,面试官更关注候选人如何将SQL的基础知识应用于解决实际问题。本文将介绍一些常见的SQL面试问题及其解决方案,帮助在面试中更好地展示技术能力。
SQL(Structured Query Language)是一种用于关系型数据库管理系统(RDBMS)的标准语言,用于与数据库进行交互。自1970年发明以来,SQL已成为维护关系数据库的知名工具,可以创建数据库和表、插入记录、删除记录、查询记录和更新记录等。
在面试中,通常会提供几个数据表以供查询。本文考虑了两个表:“Employee_detail”和“Employee_salary”。第一个表包含了IT员工的基本资料,如ID、姓名、职位、城市和入职日期。第二个表包含了员工的薪资信息,如净收入、变动部分和ID。
以下是Employee_detail表的结构和数据示例:
Row_num | EmpId | FullName | Designation | DateOfJoining | City
1 | 121 | Rachit Tomar | Apprentice | 01/31/2014 | Paris
2 | 321 | Jag Reddy | Developer | 01/30/2015 | New Delhi
3 | 421 | Vasa Trisha | Team Lead | 27/11/2016 | Chennai
以下是Employee_salary表的结构和数据示例:
EmpId | NetPay | Variable
121 | 85000 | 2000
321 | 10000 | 5000
421 | 70000 | 3000
以下是一些常见的SQL面试问题及其解决方案,这些问题覆盖了从基本查询到更复杂的数据处理技术。
以下是两种找出员工第二高薪资的方法:
-- 使用N-1规则
SELECT DISTINCT NetPay FROM Employee_salary e1 WHERE 1 = (SELECT COUNT(DISTINCT Salary) FROM Employee_salary e2 WHERE e2.NetPay > e1.NetPay);
-- 使用max聚合函数
SELECT MAX(NetPay) FROM Employee_salary WHERE NetPay NOT IN (SELECT MAX(NetPay) FROM Employee_salary);
这两种方法都能有效找出第二高的薪资,但实现方式不同。第一种方法通过比较和计数来实现,而第二种方法通过排除最高薪资来找到第二高薪资。
以下是两种查询薪资在60k到95k之间的员工详情的方法:
-- 使用大于和小于操作符
SELECT * FROM Employee_salary WHERE NetPay >= 60000 AND NetPay <= 95000;
-- 使用BETWEEN操作符
SELECT * FROM Employee_salary WHERE NetPay BETWEEN 60000 AND 95000;
这两种查询都使用了简单的关系操作符和BETWEEN关键字来检查薪资范围。
以下是两种查询名字不以V、R或S开头的员工详情的方法:
-- 使用NOT操作符
SELECT * FROM Employee_detail WHERE FullName LIKE '[!VRS]%';
-- 使用NOT LIKE操作符
SELECT * FROM Employee_detail WHERE FullName NOT LIKE '[VRS]%';
这两种方法都使用了LIKE关键字进行模式匹配,通过比较FullName字段的第一个字母与V、R、S,如果不匹配,则显示该行。
以下是两种创建新表的方法,一种不包含数据,另一种包含数据:
-- 创建不包含数据的新表
CREATE TABLE Employee_details2 AS SELECT * FROM Employee_detail WHERE 1=2;
-- 创建包含数据的新表
CREATE TABLE Employee_details2 AS SELECT * FROM Employee_detail;
这两种方法都使用了AS关键字来引用另一个表,并使用了一个假条件(1=2)来限制新表中的数据输入。
以下是显示Employee_detail表的前50%和后50%记录的方法:
-- 显示前50%记录
SELECT row_num, e1.* FROM Employee_detail e1 WHERE row_num <= (SELECT COUNT(*)/2 FROM Employee_detail);
-- 显示后50%记录
SELECT row_num, e1.* FROM Employee_detail e1
MINUS
SELECT row_num, e2.* FROM Employee_detail e2 WHERE row_num <= (SELECT COUNT(*)/2 FROM Employee_detail);
这两种查询都使用了COUNT(*)函数来计算总行数,然后使用'/'操作符将它们分成两部分。
以下是两种获取Employee_detail表中唯一记录的方法:
-- 使用DISTINCT关键字
SELECT DISTINCT * FROM Employee_detail;
-- 不使用DISTINCT关键字
SELECT * FROM Employee_detail UNION SELECT * FROM Employee_detail;
这两种方法都使用了UNION关键字来比较Employee_detail表与自身,并只打印唯一的记录。
以下是将字符串“SHIKHA”分割成多列的方法:
SELECT SUBSTR('SHIKHA', Level, 1) FROM Dual CONNECT BY Level <= LENGTH('SHIKHA');
这种方法使用了SUBSTR()函数来获取给定字符串的子字符串,Level用于找到列的层次级别,Connect By定义了父子层次关系,Length()函数计算传递的字符串的大小,Dual是Oracle创建的虚拟表。
以下是使用单条查询进行电子邮件验证的方法:
SELECT Email_id FROM Employee_detail WHERE NOT REGEXP_LIKE(Email_id, '[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,4}', 'i');
这种方法使用了REGEXP_LIKE聚合函数进行电子邮件验证,正则表达式设置了有效电子邮件的规则,LIKE将比较并匹配字符串。
以下是计算并删除Employee_detail表中的重复行的方法:
-- 计算重复行
SELECT EmpId, COUNT(EmpId) FROM Employee_detail GROUP BY EmpId HAVING COUNT(EmpId) > 1 ORDER BY COUNT(EmpId) DESC;
-- 删除重复行
DELETE FROM Employee_detail e1 WHERE EmpId = (SELECT MAX(EmpId) FROM Employee_detail e2 WHERE e1.EmpId = e2.EmpId);
-- 找出偶数行
SELECT * FROM (SELECT row_num AS rn, Ed.* FROM Employee_detail Ed) WHERE MOD(rn, 2) = 0;
-- 找出奇数行
SELECT * FROM (SELECT row_num AS rn, Ed.* FROM Employee_detail Ed) WHERE MOD(rn, 2) = 1;