子查询和JOIN的用法和区别

引言

在数据库查询中,子查询和JOIN是两个常用的工具,用于从数据库中检索和组织数据。这篇文章将介绍这两者的用法和区别,以帮助读者更好地理解如何在SQL中利用它们。

一、表结构和数据

sql 复制代码
CREATE TABLE Task (
    task_id INT PRIMARY KEY AUTO_INCREMENT,
    title VARCHAR(255) NOT NULL,
    description TEXT,
    status VARCHAR(50),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE WorkHour (
    workhour_id INT PRIMARY KEY AUTO_INCREMENT,
    task_id INT,
    hours_spent DECIMAL(8, 2) NOT NULL,
    work_date DATE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (task_id) REFERENCES Task(task_id)
);

INSERT INTO Task (title, description, status) VALUES
    ('Task 1', 'Description for Task 1', 'In Progress'),
    ('Task 2', 'Description for Task 2', 'Completed'),
    ('Task 3', 'Description for Task 3', 'Not Started');

INSERT INTO WorkHour (task_id, hours_spent, work_date) VALUES
    (1, 5.5, '2023-01-01'),
    (1, 2.0, '2023-01-02'),
    (2, 3.0, '2023-01-02'),
    (2, 4.5, '2023-01-03'),
    (3, 6.0, '2023-01-01');

二、子查询的用法

0. 子查询的基本概念

子查询是指在查询语句内嵌套另一个查询语句,将嵌套的查询的结果用于主查询。它可以出现在SELECT、FROM、WHERE或HAVING子句中,执行不同的任务。

1. 在WHERE子句中使用子查询

例如,可以使用子查询在同一表中找到工时超过10小时的任务:

sql 复制代码
SELECT task_id, title
FROM Task
WHERE task_id IN (SELECT task_id FROM WorkHour WHERE hours_spent > 10);

2. 在SELECT子句中使用子查询

子查询也可以用于在SELECT子句中执行聚合操作,例如计算每个任务的平均工时:

sql 复制代码
SELECT task_id, title, (SELECT AVG(hours_spent) FROM WorkHour WHERE Task.task_id = WorkHour.task_id) AS avg_hours
FROM Task;

3. 在 FROM 子句中使用子查询:查询每个任务及其对应的工时总和

在 FROM 子句中使用子查询:查询每个任务及其对应的工时总和

  1. 第一种:先算出总和然后join连表
  2. 第二种:先连表join然后分组算总和
sql 复制代码
SELECT Task.task_id, Task.title, TotalHours.total_hours
FROM Task
LEFT JOIN (
    SELECT task_id, SUM(hours_spent) AS total_hours
    FROM WorkHour
    GROUP BY task_id
) AS TotalHours ON Task.task_id = TotalHours.task_id;

4. 在 HAVING 子句中使用子查询:找到工时总和超过6小时的任务

sql 复制代码
SELECT Task.task_id, Task.title, COALESCE(SUM(WorkHour.hours_spent), 0) AS total_hours
FROM Task
LEFT JOIN WorkHour ON Task.task_id = WorkHour.task_id
GROUP BY Task.task_id, Task.title
HAVING total_hours > 6;

子查询也可以用于在SELECT子句中执行聚合操作,例如计算每个任务的平均工时:

sql 复制代码
SELECT Task.task_id, Task.title, TotalHours.total_hours
FROM Task
LEFT JOIN (
    SELECT task_id, SUM(hours_spent) AS total_hours
    FROM WorkHour
    GROUP BY task_id
) AS TotalHours ON Task.task_id = TotalHours.task_id;

三、JOIN的用法

0. JOIN的基本概念

JOIN用于在多个表之间建立关联,通过共享列将它们连接在一起。JOIN操作通常用于处理多表关系,执行更复杂的数据检索任务。上述的业务有人喜欢子查询去实现,但有人喜欢先将表连一起,再做处理,下面我们来看看join如何实现上述业务的。

1. 使用JOIN连接表

例如,使用INNER JOIN找到工时超过2小时的任务:

sql 复制代码
SELECT Task.task_id, Task.title
FROM Task
INNER JOIN WorkHour ON Task.task_id = WorkHour.task_id
WHERE WorkHour.hours_spent > 2;

2. 查询每个任务的平均工时

sql 复制代码
SELECT Task.task_id, Task.title, AVG(WorkHour.hours_spent) AS avg_hours
FROM Task
LEFT JOIN WorkHour ON Task.task_id = WorkHour.task_id
GROUP BY Task.task_id, Task.title;

3. 查询每个任务及其对应的工时总和

sql 复制代码
SELECT Task.task_id, Task.title, COALESCE(SUM(WorkHour.hours_spent), 0) AS total_hours
FROM Task
LEFT JOIN WorkHour ON Task.task_id = WorkHour.task_id
GROUP BY Task.task_id, Task.title;

四、区别和适用场景

1. 可读性和语法简洁性

子查询通常更直观,语法相对简单,对于一些简单的嵌套查询场景更易于理解。JOIN语句在处理多表关联时提供了更清晰的语法。

2. 性能

在性能方面,JOIN通常更为高效,尤其是在大型数据集上。数据库系统可以通过优化JOIN操作来提高查询效率。

3. 子查询的适用场景

  • 在同一表内部执行比较、过滤和聚合操作时。
  • 用于在WHERE子句中进行条件过滤。
  • 在SELECT子句中执行嵌套聚合操作。

4. JOIN的适用场景

  • 处理多表关联,解决复杂的查询需求。
  • 查询多个表之间的关系,进行更灵活的数据检索。
  • 需要在查询中使用多个表的列时。

五、结论

子查询和JOIN是SQL中强大的工具,各有其优势。在实际应用中,根据具体需求和数据模型,选择使用哪种方式是关键。可读性、性能、适用场景等因素都应该被综合考虑,以确保查询既正确又高效。根据情况选择合适的工具,将有助于编写清晰、高效的数据库查询。 通常情况下,JOIN 和子查询都可以用来实现相同的功能,但它们在某些情况下可能有不同的性能表现,并且在某些情境下更适合使用一种而不是另一种。

下面是一些比较 JOIN 和子查询的一般指导原则:

  1. 可读性: 子查询通常对于理解查询的意图更直观,因为它们嵌套在主查询中。在某些情况下,子查询可以使 SQL 查询更易读。

  2. 性能: 在某些情况下,JOIN 操作可能比子查询更高效。数据库系统可以通过优化 JOIN 操作来更有效地执行查询。然而,优化可能因数据库引擎而异,有时子查询可能更为高效。

  3. 存在性: JOIN 通常用于关联两个或多个表,而子查询通常用于在单个表中进行嵌套查询。如果您需要关联表,则使用 JOIN 更合适。如果只是在单个表中进行嵌套查询,可以考虑使用子查询。

在单个表中进行嵌套查询通常指的是在同一个表中的子查询。这种情况可能包括对表中的某些列进行聚合、过滤或比较,并将子查询的结果用作主查询的一部分。

  1. 聚合函数的使用: 如果您想在同一表的不同行之间执行聚合函数(如计算总和、平均值、最大值等),则可以考虑使用子查询。例如,找到表中所有销售额高于平均销售额的行:

    sql 复制代码
    SELECT * FROM sales
    WHERE amount > (SELECT AVG(amount) FROM sales);
  2. 子查询作为过滤条件: 如果您想根据同一表中的子集行进行过滤,可以使用子查询作为过滤条件。例如,找到所有销售额高于某个阈值的销售记录:

    sql 复制代码
    SELECT * FROM sales
    WHERE customer_id IN (SELECT customer_id FROM sales WHERE amount > 1000);
  3. 比较列与子查询结果: 比较表中的某一列与子查询的结果,以确定是否满足某些条件。例如,找到比某个日期之后注册的所有用户:

    sql 复制代码
    SELECT * FROM users
    WHERE registration_date > (SELECT MAX(registration_date) FROM users);

总的来说,单个表中的嵌套查询主要用于在同一表内部执行比较、过滤和聚合操作。这可以帮助您根据表内的某些条件选择特定的行。

  1. 复杂性: 在一些情况下,使用 JOIN 可以更容易理解和维护,尤其是在处理多个表之间的复杂关系时。

在实际应用中,性能往往是一个关键因素,您可能需要根据您的具体数据库和数据模型测试和优化查询性能。在一些情况下,选择 JOIN 或子查询可能取决于具体的查询要求、数据量和索引的使用情况。

相关推荐
潘多编程22 分钟前
Spring Boot微服务架构设计与实战
spring boot·后端·微服务
2402_8575893627 分钟前
新闻推荐系统:Spring Boot框架详解
java·spring boot·后端
2401_8576226629 分钟前
新闻推荐系统:Spring Boot的可扩展性
java·spring boot·后端
读心悦1 小时前
修改 MySQL 数据库中的唯一键
数据库·mysql
qq_213157891 小时前
(c#)unity中sqlite多线程同时开启事务会导致非常慢
数据库·sqlite·c#
北极无雪1 小时前
Spring源码学习(拓展篇):SpringMVC中的异常处理
java·开发语言·数据库·学习·spring·servlet
666xiaoniuzi2 小时前
深入理解 C 语言中的内存操作函数:memcpy、memmove、memset 和 memcmp
android·c语言·数据库
正在走向自律2 小时前
3.使用条件语句编写存储过程(3/10)
数据库·存储过程·安全架构
YONG823_API2 小时前
电商平台数据批量获取自动抓取的实现方法分享(API)
java·大数据·开发语言·数据库·爬虫·网络爬虫
小小不董2 小时前
图文深入理解Oracle DB Scheduler
linux·运维·服务器·数据库·oracle