1、子查询
子查询是一个嵌套在其他查询中的查询,用于提供额外的数据过滤、计算或子集。子查询可以出现在SELECT
, FROM
, WHERE
或HAVING
子句中。子查询是一个非常强大的工具,它可以让在单个查询中执行多级数据计算。正确使用子查询能大大增强SQL的功能,使复杂数据关系的查询变得可能。
1)在WHERE子句中使用子查询
有一个名为employees的表格,其中包含员工的信息,包括他们的部门和工资。要找出工资高于其部门平均工资的员工,如下,
SELECT employee_id, name, salary FROM employees WHERE salary > (SELECT AVG(salary) FROM employees AS e WHERE e.department_id = employees.department_id);
2) 在SELECT子句中使用子查询
需要在查询结果中显示每个员工的工资与其部门平均工资的差异,如下,
SELECT employee_id, name, salary, (SELECT AVG(salary) FROM employees AS e WHERE e.department_id = employees.department_id) AS department_avg, salary - (SELECT AVG(salary) FROM employees AS e WHERE e.department_id = employees.department_id) AS diff_from_avg FROM employees;
3)在FROM子句中使用子查询
可以使用子查询创建一个临时表格,然后从这个表格中进行选择。如找出每个部门工资最高的员工,如下,
SELECT e.* FROM employees e INNER JOIN (SELECT department_id, MAX(salary) AS max_salary FROM employees GROUP BY department_id) AS max_salaries ON e.department_id = max_salaries.department_id AND e.salary = max_salaries.max_salary;
4)在HAVING子句中使用子查询
要找出平均工资高于公司整体平均工资的部门,如下,
SELECT department_id, AVG(salary) AS average_salary FROM employees GROUP BY department_id HAVING AVG(salary) > (SELECT AVG(salary) FROM employees);
2、公用表表达式 (CTE)
公用表表达式(Common Table Expressions,简称CTE)是SQL查询中的一个强大工具,可以将查询结果暂时命名并在后续的查询中重复使用。CTE的使用可以使查询变得更加模块化、易于理解和维护。CTE尤其有用于复杂查询的构建,可以将复杂的逻辑分解成简单、模块化的部分。
1)基础CTE用法
有一个员工表employees,其中包含员工的ID、姓名和部门ID。要找出每个部门的员工数量,如下,
WITH DepartmentCounts AS ( SELECT department_id, COUNT(*) AS num_employees FROM employees GROUP BY department_id ) SELECT * FROM DepartmentCounts;
2)多层CTE
公用表表达式可以嵌套使用,使得处理多步骤的数据分析变得更简单。比如,要从员工表中找到每个部门平均工资最高的三个部门,如下,
WITH DepartmentSalary AS ( SELECT department_id, AVG(salary) AS average_salary FROM employees GROUP BY department_id ), TopDepartments AS ( SELECT department_id FROM DepartmentSalary ORDER BY average_salary DESC LIMIT 3 ) SELECT e.department_id, e.name, e.salary FROM employees e JOIN TopDepartments td ON e.department_id = td.department_id;
3)递归CTE
递归CTE可以用来处理层级或递归关系,如组织结构或树形结构。假设我们有一个组织结构表organization,其中包含员工ID和上级ID,要为每个员工创建一个层级列表,如下 ,
WITH RECURSIVE OrgChart AS ( SELECT employee_id, supervisor_id, 1 AS depth FROM organization WHERE supervisor_id IS NULL UNION ALL SELECT o.employee_id, o.supervisor_id, oc.depth + 1 FROM organization o INNER JOIN OrgChart oc ON o.supervisor_id = oc.employee_id ) SELECT * FROM OrgChart;
3、 窗口函数
窗口函数(Window Functions)是SQL的强大功能之一,可以在数据集的"窗口"上执行计算,这些窗口根据指定的条件对行进行分组。窗口函数对于执行如排名、累计、移动平均等操作非常有用,而且不需要将数据实际分组到单独的输出行中,因此可以保留详细的行级数据。窗口函数是一种特殊的函数,可以对查询结果集中的一组行进行计算,并返回一个与每行关联的值。常见的窗口函数包括排名函数(ROW_NUMBER()
, RANK()
, DENSE_RANK()
)、聚合函数(SUM()
, AVG()
, COUNT()
)以及累积函数(SUM()
OVER()
)等。
1)排名函数
ROW_NUMBER()
:为每一行分配一个唯一的连续整数。
RANK()
:为相同值的行分配相同的排名,但会在下一个值上留出空白(例如 1, 2, 2, 4)。
DENSE_RANK()
:与RANK()
类似,但排名之间没有间隔(例如 1, 2, 2, 3)。
SELECT product_id, sales, ROW_NUMBER() OVER (ORDER BY sales DESC) AS row_number, RANK() OVER (ORDER BY sales DESC) AS rank, DENSE_RANK() OVER (ORDER BY sales DESC) AS dense_rank FROM sales_records;
2)聚合窗口函数
SUM()
、AVG()
、MAX()
、MIN()
:在窗口中计算总和、平均值、最大值和最小值。计算每个员工在每个部门的累计销售总额,如下,
SELECT employee_id, department_id, sales, SUM(sales) OVER (PARTITION BY department_id ORDER BY sales_date) AS cumulative_sales FROM sales_records;
3) 移动平均和累积
LEAD()、LAG():获取窗口中当前行的前一行或后一行的数据。
移动平均:使用窗口函数计算移动平均值。
计算每个产品的当前月销售与前两月销售的平均值,如下,
SELECT product_id, sales_month, sales, AVG(sales) OVER (PARTITION BY product_id ORDER BY sales_month ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS moving_average FROM monthly_sales;
4)首值与尾值
窗口函数通过指定OVER()子句来定义窗口的分组方式和排序规则。PARTITION BY
子句用于在不同的分区中独立计算每个窗口,而ORDER BY
子句则用于数据排序。FIRST_VALUE()
、LAST_VALUE()
是在窗口内获取一组值的第一个或最后一个。显示每个部门中薪资最高的员工的薪资。如下,
SELECT employee_id, department_id, salary, FIRST_VALUE(salary) OVER (PARTITION BY department_id ORDER BY salary DESC) AS highest_salary FROM employees;