今天介绍下关于高级查询的详细介绍,包括子查询、连接查询、分组查询等,并结合MySQL数据库提供实际例子。
一、子查询(Subqueries)
子查询是嵌套在另一个查询中的查询语句,通常用于提供条件过滤、生成临时数据集等。子查询可以出现在SELECT、FROM、WHERE、HAVING等子句中。
1. 标量子查询(Scalar Subquery)
标量子查询返回单个值,通常用于比较操作。
示例1:查询工资高于平均工资的员工
SELECT employee_id, name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);
解释:外层查询从employees表中获取员工信息,内层子查询计算所有员工的平均工资,外层查询的WHERE子句将筛选出工资高于平均工资的员工。
示例2:查询与员工Alice同部门的其他员工
SELECT employee_id, name
FROM employees
WHERE department_id = (SELECT department_id FROM employees WHERE name = 'Alice');
解释:内层子查询找到Alice所在的部门ID,外层查询根据这个部门ID筛选出其他同部门的员工。
2. 行子查询(Row Subquery)
行子查询返回一行数据,通常用于比较操作符(如IN、ANY、ALL)。
示例1:查询工资高于部门平均工资的员工
SELECT e.employee_id, e.name, e.salary
FROM employees e
WHERE (e.department_id, e.salary) > ANY (SELECT department_id, AVG(salary)FROM employeesGROUP BY department_id
);
解释:内层子查询按部门分组计算每个部门的平均工资,外层查询使用ANY比较操作符,筛选出工资高于所在部门平均工资的员工。
示例2:查询与Alice和Bob同部门的员工
SELECT employee_id, name
FROM employees
WHERE (department_id, name) IN (SELECT department_id, nameFROM employeesWHERE name IN ('Alice', 'Bob')
);
解释:内层子查询找到Alice和Bob的部门ID和姓名,外层查询使用IN操作符筛选出与他们同部门的员工。
3. 表子查询(Table Subquery)
表子查询返回一个表,通常用于FROM子句中。
示例1:查询每个部门工资最高的员工
SELECT e.employee_id, e.name, e.salary, e.department_id
FROM employees e
JOIN (SELECT department_id, MAX(salary) AS max_salaryFROM employeesGROUP BY department_id
) AS max_sal
ON e.department_id = max_sal.department_id AND e.salary = max_sal.max_salary;
解释:内层子查询按部门分组,计算每个部门的最高工资。外层查询通过JOIN将employees表与子查询结果连接,筛选出每个部门工资最高的员工。
示例2:查询每个部门的员工数量和平均工资
SELECT d.department_id, d.department_name, COUNT(e.employee_id) AS employee_count, AVG(e.salary) AS avg_salary
FROM departments d
LEFT JOIN employees e
ON d.department_id = e.department_id
GROUP BY d.department_id, d.department_name;
解释:虽然这里没有显式的表子查询,但LEFT JOIN的结果可以视为一个表子查询。查询统计了每个部门的员工数量和平均工资。
二、连接查询(Joins)
连接查询用于将两个或多个表中的数据组合在一起。MySQL支持多种连接类型,包括INNER JOIN、LEFT JOIN、RIGHT JOIN、FULL JOIN(MySQL不支持FULL JOIN,但可以通过UNION实现)。
1. 内连接(INNER JOIN)
内连接返回两个表中匹配的行。
示例1:查询员工及其所在部门的信息
SELECT e.employee_id, e.name, d.department_name
FROM employees e
INNER JOIN departments d
ON e.department_id = d.department_id;
解释:INNER JOIN将employees表和departments表连接,返回员工及其所在部门的信息。
示例2:查询员工及其经理的信息
SELECT e.employee_id, e.name AS employee_name, m.name AS manager_name
FROM employees e
INNER JOIN employees m
ON e.manager_id = m.employee_id;
解释:employees表自连接,e表示员工,m表示经理,查询返回每个员工及其经理的名称。
2. 外连接(Outer Join)
外连接返回一个表中的所有行,即使另一个表中没有匹配的行。
示例1:查询所有员工及其所在部门的信息,即使某些员工没有分配部门
SELECT e.employee_id, e.name, d.department_name
FROM employees e
LEFT JOIN departments d
ON e.department_id = d.department_id;
解释:LEFT JOIN确保返回employees表中的所有行,即使departments表中没有匹配的行(部门名称为NULL)。
示例2:查询所有部门及其员工的信息,即使某些部门没有员工
SELECT d.department_id, d.department_name, e.name AS employee_name
FROM departments d
LEFT JOIN employees e
ON d.department_id = e.department_id;
解释:LEFT JOIN确保返回departments表中的所有行,即使employees表中没有匹配的行(员工名称为NULL)。
3. 自连接(Self Join)
自连接是将一个表与自身连接,通常用于比较表中的不同行。
示例1:查询员工及其直接上级的信息
SELECT e.employee_id, e.name AS employee_name, m.name AS manager_name
FROM employees e
JOIN employees m
ON e.manager_id = m.employee_id;
解释:employees表自连接,e表示员工,m表示经理,查询返回每个员工及其直接上级的名称。
示例2:查询员工及其所有上级的信息(多级)
WITH RECURSIVE EmployeeHierarchy AS (SELECT employee_id, name, manager_id, 1 AS levelFROM employeesWHERE manager_id IS NULL -- 假设经理ID为NULL表示最高级UNION ALLSELECT e.employee_id, e.name, e.manager_id, eh.level + 1FROM employees eJOIN EmployeeHierarchy ehON e.manager_id = eh.employee_id
)
SELECT employee_id, name, manager_id, level
FROM EmployeeHierarchy;
解释:使用递归公用表表达式(CTE)实现多级自连接,查询每个员工及其所有上级的信息。
三、分组查询(GROUP BY)
分组查询用于将数据按指定列分组,并对每个分组进行聚合计算。GROUP BY子句通常与聚合函数(如SUM、AVG、COUNT等)一起使用。
1. 基本分组
按指定列分组并计算聚合值。
示例1:查询每个部门的员工数量
SELECT department_id, COUNT(employee_id) AS employee_count
FROM employees
GROUP BY department_id;
解释:按department_id分组,计算每个部门的员工数量。
示例2:查询每个部门的平均工资
SELECT department_id, AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id;
解释:按department_id分组,计算每个部门的平均工资。
2. 分组过滤(HAVING)
HAVING子句用于过滤分组后的结果,与WHERE子句不同,HAVING子句可以使用聚合函数。
示例1:查询员工数量大于5的部门
SELECT department_id, COUNT(employee_id) AS employee_count
FROM employees
GROUP BY department_id
HAVING COUNT(employee_id) > 5;
解释:按department_id分组,使用HAVING子句过滤出员工数量大于5的部门。
示例2:查询平均工资大于5000的部门
SELECT department_id, AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id
HAVING AVG(salary) > 5000;
解释:按department_id分组,使用HAVING子句过滤出平均工资大于5000的部门。
3. 分组排序(ORDER BY)
ORDER BY子句用于对分组后的结果进行排序。
示例1:查询每个部门的员工数量,并按员工数量降序排序
SELECT department_id, COUNT(employee_id) AS employee_count
FROM employees
GROUP BY department_id
ORDER BY employee_count DESC;
解释:按department_id分组,计算每个部门的员工数量,并按员工数量降序
以上就是基于Mysql,有关查询相关的进阶知识,希望对你有所帮助~
后续会连续发布多篇SQL进阶相关内容;
期待你的关注,学习更多知识;