今天介绍下关于高级查询的详细介绍,包括子查询、连接查询、分组查询等,并结合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进阶相关内容;
期待你的关注,学习更多知识;