5 子查询
SQL中的子查询是用于从一个或多个表中检索数据的嵌套查询,子查询的结果在主查询中使用。它们可用于过滤、排序和分组数据,并可分类为单行或多行子查询。子查询括在括号中,可以在SQL语句的各个部分中使用,例如SELECT、FROM、WHERE和HAVING子句。
例如;有两个名为employees
和salaries
的表。employees
表包含以下列:employee_id
、first_name
、last_name
和department_id
。salaries
表包含以下列:employee_id
、salary
和salary_date
。您想要找到每个部门工资最高的员工的姓名。为此,您可以使用子查询查找每个部门的最高工资,然后将结果与employees和salaries表连接以获取具有该工资的员工的姓名。
下面的查询使用子查询查找每个部门的最高工资。首先执行子查询并返回包含每个部门最高工资的结果集。然后,主查询将employees
和salaries
表与子查询的结果连接,以获取每个部门工资最高的员工的姓名。
SELECT
e.first_name,
e.last_name,
e.department_id,
s.salary
FROM
employees e
INNER JOIN salaries s ON e.employee_id = s.employee_id
INNER JOIN (
SELECT
department_id,
MAX(salary) AS max_salary
FROM
salaries
GROUP BY
department_id
) m ON s.department_id = m.department_id AND s.salary = m.max_salary;
使用INNER JOIN子句将employees
和salaries
表连接起来,使用employee_id
列作为连接键。使用department_id
列将子查询连接到主查询,并使用salary
列匹配每个部门的最高工资。
查询的结果是一个表格,显示每个部门工资最高的员工的姓名及其部门ID和工资。
6 交叉连接
交叉连接是一种连接操作,用于返回两个或多个表的所有可能行组合,而不需要连接条件。它在生成测试数据或需要获取多个表格所有可能组合的计算时非常有用。然而,由于交叉连接可能会产生高计算成本和庞大的结果集,因此在使用时需要谨慎考虑其影响,并确保结果集的大小符合预期。通常情况下,应优先考虑使用其他类型的连接操作,如内连接、外连接或等值连接,以更有效地获取所需的数据。
在下面的示例中,有两个名为customers
和orders
的表。customers
表包含以下列:customer_id
、customer_name
和city
。orders
表包含以下列:order_id
、customer_id
和order_date
。您想要找到每个客户在每个城市下单的总数。为此,您可以使用交叉连接生成一个结果集,将每个客户与每个城市组合,然后将结果与orders
表连接以获取每种组合的订单数量。
SELECT
c.customer_id,
c.customer_name,
c.city,
COUNT(o.order_id) AS order_count
FROM
customers c
CROSS JOIN (
SELECT DISTINCT
city
FROM
customers
) cities
LEFT JOIN orders o ON c.customer_id = o.customer_id
WHERE
c.city = cities.city
GROUP BY
c.customer_id,
c.customer_name,
c.city;
示例中,查询使用交叉连接生成一个结果集,该结果集将每个客户与每个城市组合在一起。交叉连接首先执行,返回一个包含每个客户和城市的每个组合的结果集。然后,主查询使用左连接将交叉连接的结果与orders
表连接,以确保即使客户没有下订单也包括所有客户在结果中。
WHERE
子句用于过滤结果,仅包括客户所在城市与交叉连接中的城市匹配的行。这确保了结果仅显示每个客户在其各自城市中的订单数量。
GROUP BY
子句用于按客户ID、客户名称和城市分组结果。COUNT()
函数用于计算每个客户在每个城市中的订单数量。
查询的结果是一个表格,显示了每个客户在每个城市中下达的订单总数。
7 临时表
SQL中的临时表是在执行SQL语句或事务期间创建和使用的表。它们存储在内存或磁盘上,并在创建它们的会话结束或不再需要时自动删除。临时表通常用于存储中间结果,或将复杂查询分解为更小、更易管理的部分。
它们可以使用CREATE TEMPORARY TABLE语句创建,并像常规表一样使用SQL命令(如SELECT、INSERT、UPDATE和DELETE)进行操作。临时表可以非常有用,用于优化复杂查询并提高性能,因为它们可以帮助减少需要在任何给定时间处理的数据量。
假设有一个名为sales
的表,其中包含以下列:date
、product
、category
和sales_amount
。您想创建一个报告,显示过去一年每个月每个类别的总销售额。为此,您可以使用一个临时表来创建每个月销售数据的摘要,然后将临时表与sales
表连接,以获取每个类别的总销售额。
首先,您可以使用CREATE TEMPORARY TABLE
语句创建临时表:
CREATE TEMPORARY TABLE monthly_sales_summary (
month DATE,
category VARCHAR(50),
total_sales DECIMAL(10,2)
);
此语句创建了一个名为monthly_sales_summary
的临时表,其中包含三列:month
、category
和total_sales
。month
列的类型为DATE
,category
列的类型为VARCHAR(50)
,total_sales
列的类型为DECIMAL(10,2)
。
接下来,使用INSERT INTO
语句将摘要数据填充到临时表中:
INSERT INTO monthly_sales_summary (month, category, total_sales)
SELECT
DATE_TRUNC('month', date) AS month,
category,
SUM(sales_amount) AS total_sales
FROM
sales
WHERE
date >= DATE_TRUNC('year', CURRENT_DATE) -- sales from the past year
GROUP BY
DATE_TRUNC('month', date),
category;
此语句使用DATE_TRUNC
函数将date
列截断到月份级别,按月份和类别分组销售数据。此查询的结果插入到monthly_sales_summary
表中,该表现在包含每个月销售数据的摘要。
最后,可以将临时表与sales
表连接起来,以获取每个类别的总销售额:
SELECT
s.category,
mss.month,
mss.total_sales
FROM
sales s
JOIN monthly_sales_summary mss
ON s.category = mss.category
AND DATE_TRUNC('month', s.date) = mss.month
WHERE
s.date >= DATE_TRUNC('year', CURRENT_DATE) -- sales from the past year
ORDER BY
s.category,
mss.month;
此语句将sales
表与monthly_sales_summary
表连接在category
和month
列上,并从临时表中选择category
、month
和total_sales
列。WHERE
子句用于过滤结果,仅包括过去一年的销售数据,ORDER BY
子句用于按类别和月份对结果进行排序。
查询的结果是一个表格,显示了过去一年每个月每个类别的总销售额。
8 具体化视图
SQL中的具体化视图是存储为物理表的预计算结果集。它们基于SQL查询创建和维护,并用于提高频繁执行查询的性能。具体化视图可以按计划或按需刷新,以确保数据是最新的。当针对具体化视图执行查询时,结果集从物理表中检索,而不是从原始表中计算。
这可以提升性能,特别是对于涉及联接或聚合函数的复杂查询。具体化视图通常用于数据仓库和业务智能应用程序中,在这些应用程序中,它们可以帮助加速报告和仪表板。
例如,有一个名为sales
的大型表,其中包含以下列:date
、product
、category
和sales_amount
。您想创建一个报告,显示过去一年每个月每个类别的总销售额。但是,直接在sales
表上运行此查询会很慢,因为它包含数百万行。为了加快查询速度,可以创建一个物化视图,按月份和类别汇总销售数据。
要创建物化视图,可以使用CREATE MATERIALIZED VIEW
语句,如下所示:
CREATE MATERIALIZED VIEW monthly_sales_summary AS
SELECT
DATE_TRUNC('month', date) AS month,
category,
SUM(sales_amount) AS total_sales
FROM
sales
WHERE
date >= DATE_TRUNC('year', CURRENT_DATE) -- sales from the past year
GROUP BY
DATE_TRUNC('month', date),
category;
此语句创建了一个名为monthly_sales_summary
的物化视图,其中包含每个月和类别的销售数据摘要。SELECT
语句与前面示例中用于创建临时表的语句相同,但是不使用临时表,而是将结果存储在物化视图中。
物化视图与表类似,因为它们将数据存储在磁盘上,但是在基础数据更改时会自动更新。您可以使用REFRESH MATERIALIZED VIEW
语句手动刷新物化视图,也可以使用cron作业或其他调度工具设置定期刷新。
创建物化视图后,可以像查询其他表一样查询它:
SELECT
category,
month,
total_sales
FROM
monthly_sales_summary
ORDER BY
category,
month;
此语句从monthly_sales_summary
物化视图中选择category
、month
和total_sales
列,并按类别和月份对结果进行排序。
在这种情况下使用物化视图的优点在于,它允许您预计算和存储摘要数据,从而减少运行查询所需的时间。物化视图特别适用于经常运行并需要对大型数据集进行复杂计算的报告。但是,它们也有一些限制,例如它们可能占用大量磁盘空间,并且在基础数据更改时可能无法立即更新。
结语
掌握高级SQL技术,如窗口函数、CTE、聚合函数、透视表、子查询、交叉连接、临时表和物化视图,可以帮助您更有效地处理复杂的数据分析任务。
发表评论