再探再报:SQL中的关联查询

在 SQL 中进行关联查询(或称联接查询)时,有几种不同的语法来执行这些查询,常见的包括:

  1. 使用 JOIN 关键字JOIN 关键字可与不同类型的联接组合使用,如 INNER JOINLEFT JOINRIGHT JOINFULL JOIN 等。例如:

    sql 复制代码
    SELECT *
    FROM TableA
    INNER JOIN TableB ON TableA.column = TableB.column;

    这种语法通过 ON 关键字指定连接条件进行表联接。

  2. 使用逗号分隔表 :在 FROM 子句中可以列出多个表名,使用逗号分隔。但不推荐在实际应用中使用这种方式,因为它与 ANSI SQL 标准不太一致,并且可读性较差。示例:

    sql 复制代码
    SELECT *
    FROM TableA, TableB
    WHERE TableA.column = TableB.column;

    此种方式实际上会执行笛卡尔积,然后通过 WHERE 子句进行过滤以得到想要的结果。不过,应该尽量避免使用这种语法,而是采用显式的 JOIN 语法。

  3. 子查询 :在 SELECT 语句中嵌套使用子查询来执行关联查询。例如:

    sql 复制代码
    SELECT *
    FROM TableA
    WHERE TableA.column IN (SELECT column FROM TableB WHERE condition);

    这种方式将一个查询的结果嵌套到另一个查询中,用于创建关联。这种方法适用于特定情况下的复杂查询。

以上是 SQL 中进行关联查询常用的几种语法形式。在实际应用中,推荐使用 JOIN 语法,因为它更为清晰明了,易于理解,并且符合 ANSI SQL 标准。

1.Join语法

1.1. LEFT JOIN

在数据库中,LEFT JOIN 是一种用于联结多个表的 SQL 查询语句。LEFT JOIN 返回左边表(也称为主表)中的所有记录,并且如果在右边表(也称为外部表)中存在匹配的记录,则返回匹配的记录。如果右边表中没有匹配的记录,则返回 NULL 值。

语法如下所示:

sql 复制代码
SELECT 列名列表
FROM 左边表
LEFT JOIN 右边表 ON 左边表.列名 = 右边表.列名;

这里有一个示例来说明 LEFT JOIN 的工作原理。假设有两个表 StudentsGrades

Students 表:

ID Name
1 Alice
2 Bob
3 Charlie

Grades 表:

Student_ID Grade
1 A
2 B
4 C

如果使用 LEFT JOIN 来结合这两个表,查询学生和他们的成绩(如果有的话),语句如下:

sql 复制代码
SELECT Students.Name, Grades.Grade
FROM Students
LEFT JOIN Grades ON Students.ID = Grades.Student_ID;

执行这个查询后,会得到如下结果:

Name Grade
Alice A
Bob B
Charlie NULL

这个结果解释如下:

  • Alice 和 Bob 在 Students 表和 Grades 表中都有匹配的记录,因此他们的成绩被显示出来。
  • Charlie 在 Students 表中有记录,但在 Grades 表中没有匹配的记录,因此他的成绩显示为 NULL

总之,LEFT JOIN 允许您检索左边表中的所有记录,并根据右边表中的匹配条件,返回相应的数据。如果右边表中没有匹配的记录,则返回 NULL

1.2. LEFT JOIN和INNER JOIN

INNER JOINLEFT JOIN 是 SQL 中常用的两种连接(或联结)表的方法,它们之间有一些重要的区别:

  1. INNER JOIN

    • INNER JOIN 返回两个表中满足连接条件的匹配行。

    • 结果集中只包含在两个表中都存在匹配的行。

    • 如果在左表或右表中没有匹配的行,则这些行不会出现在结果中。

    • 语法示例:

      sql 复制代码
      SELECT * FROM TableA INNER JOIN TableB ON TableA.column = TableB.column;
  2. LEFT JOIN

    • LEFT JOIN 返回左表中的所有行,以及右表中与左表中行匹配的行(如果有匹配的话)。

    • 如果右表中没有匹配的行,则在结果集中相关列显示为 NULL

    • 左表中的所有行都会出现在结果中,无论右表中是否有匹配。

    • 语法示例:

      sql 复制代码
      SELECT * FROM TableA LEFT JOIN TableB ON TableA.column = TableB.column;

举例说明:

假设有两个表:EmployeesDepartments

Employees

| EmployeeID | EmployeeName | DepartmentID |
|------------|--------------|--------------|
| 1          | Alice        | 1            |
| 2          | Bob          | 2            |
| 3          | Charlie      | 1            |

Departments 表:

| DepartmentID | DepartmentName |
|--------------|----------------|
| 1            | Sales          |
| 2            | Marketing      |
| 3            | HR             |

现在来比较 INNER JOINLEFT JOIN 的区别:

INNER JOIN 示例:

sql 复制代码
SELECT Employees.EmployeeName, Departments.DepartmentName
FROM Employees
INNER JOIN Departments ON Employees.DepartmentID = Departments.DepartmentID;

结果将是只有 Sales 和 Marketing 部门的员工信息:

| EmployeeName | DepartmentName |
|--------------|----------------|
| Alice        | Sales          |
| Bob          | Marketing      |
| Charlie      | Sales          |

注意,只有 Sales 和 Marketing 部门的员工被返回,因为只有这两个部门在 Employees 表和 Departments 表中都有匹配的记录。

LEFT JOIN 示例:

sql 复制代码
SELECT Employees.EmployeeName, Departments.DepartmentName
FROM Employees
LEFT JOIN Departments ON Employees.DepartmentID = Departments.DepartmentID;

结果将包括所有员工信息,但是对于 HR 部门(在 Departments 表中存在但在 Employees 表中没有匹配的记录),相关的部门信息显示为 NULL

| EmployeeName | DepartmentName |
|--------------|----------------|
| Alice        | Sales          |
| Bob          | Marketing      |
| Charlie      | Sales          |
| NULL         | HR             |

在这个例子中,LEFT JOIN 返回了 Employees 表中的所有员工信息,包括 HR 部门,因为它是左连接。但是,由于在 Employees 表中没有与 HR 部门相关的记录,所以在 DepartmentName 列中显示为 NULL

1.3. FULL JOIN

FULL JOIN 是 SQL 中用于连接两个表并返回它们之间所有匹配和不匹配行的联接操作。FULL JOIN 结合了 LEFT JOINRIGHT JOIN 的功能,它返回两个表中的所有行,并且对于不匹配的行,其中一个表中无对应匹配的行,相关列会显示 NULL 值。

语法结构如下:

sql 复制代码
SELECT *
FROM TableA
FULL JOIN TableB ON TableA.column = TableB.column;
  • FULL JOIN 结果包括了 LEFT JOINRIGHT JOIN 的结果,以及两个表中不匹配的行。
  • 返回的结果集包括了左表中所有的行和右表中所有的行,以及根据连接条件匹配的行。
  • 如果在连接条件中找不到匹配的行,则相关列将显示为 NULL
  • 如果一个表中有匹配而另一个表中没有匹配的行,结果集中将分别显示两个表中的数据,但没有对应的匹配值。

举个例子说明:

假设有两个表 EmployeesDepartments

Employees 表:

EmployeeID EmployeeName DepartmentID
1 Alice 1
2 Bob 2
3 Charlie 3

Departments 表:

DepartmentID DepartmentName
1 Sales
2 Marketing
4 HR

使用 FULL JOIN 进行联接:

sql 复制代码
SELECT Employees.EmployeeID, Employees.EmployeeName, Departments.DepartmentName
FROM Employees
FULL JOIN Departments ON Employees.DepartmentID = Departments.DepartmentID;

结果可能如下:

EmployeeID EmployeeName DepartmentName
1 Alice Sales
2 Bob Marketing
3 Charlie NULL
NULL NULL HR

以上结果显示了两个表中的所有行。前两行分别表示有匹配的员工和他们的部门,第三行表示一个员工在 Employees 表中有记录但在 Departments 表中没有匹配的部门信息,第四行表示在 Departments 表中有记录但在 Employees 表中没有匹配的员工信息。

1.4. CROSS JOIN

CROSS JOIN 是 SQL 中用于执行笛卡尔积(Cartesian Product)的一种联接方式。它返回两个表中所有可能的组合,即左表中的每一行都与右表中的每一行进行组合,生成一个新的虚拟表。

CROSS JOIN 不需要任何连接条件,因此它不关心两个表之间是否有相关的列或条件。它简单地将一个表的每一行与另一个表的每一行进行匹配,生成的结果行数为两个表行数的乘积。

语法如下:

sql 复制代码
SELECT *
FROM TableA
CROSS JOIN TableB;

举例说明:

假设有两个表 StudentsCourses

Students 表:

StudentID StudentName
1 Alice
2 Bob

Courses 表:

CourseID CourseName
101 Math
102 Science

使用 CROSS JOIN 进行联接:

sql 复制代码
SELECT Students.StudentID, Students.StudentName, Courses.CourseID, Courses.CourseName
FROM Students
CROSS JOIN Courses;

结果将是两个表中所有行的组合:

StudentID StudentName CourseID CourseName
1 Alice 101 Math
1 Alice 102 Science
2 Bob 101 Math
2 Bob 102 Science

在这个例子中,CROSS JOIN 返回了所有可能的学生和课程的组合,因为它不需要任何连接条件,所以它生成了两个表中所有行的笛卡尔积。需要注意的是,笛卡尔积会导致结果集行数快速增加,因此在实际应用中,应慎重使用 CROSS JOIN,特别是当两个表的行数较大时,可能会生成巨大的结果集。

2.逗号分隔表

逗号分隔表(Comma-Separated Tables)是 SQL 中一种在 FROM 子句中列出多个表的语法形式,用逗号 , 将表名分隔开来,从而允许同时查询多个表。这种语法可以用于执行表联接操作,但是它的使用方式不够明确,可读性较差,因此不推荐在实际开发中广泛使用。

2.1. 案例一

在逗号分隔表的语法中,可以列出多个表,并在查询中引用这些表。例如:

sql 复制代码
SELECT *
FROM TableA, TableB;

这样的语法形式将返回两个表的笛卡尔积。如果没有指定连接条件或者其他约束,将会生成两个表的所有可能的组合,称为笛卡尔积。

通常情况下,在逗号分隔表的写法下,如果没有指定 WHERE 子句或者其他连接条件,可能会意外地生成笛卡尔积,结果是两个表的所有行的组合。这可能会导致意外的大量数据,特别是当表中的行数很大时,这种查询会产生非常庞大的结果集。

2.2. 案例二

sql 复制代码
SELECT *
FROM TableA
INNER JOIN TableB ON TableA.id = TableB.id;

这个查询使用了逗号分隔表名的方式,并在 WHERE 子句中指定了连接条件 TableA.id = TableB.id。虽然这种写法可以执行表的联接操作,但实际上这是一个隐式的内连接。

这条查询语句会返回 TableATableB 中满足连接条件的行。在这种情况下,由于在 WHERE 子句中指定了 TableA.id = TableB.id,它执行了一个内连接,只返回两个表中在 id 列上匹配的行。

这种写法虽然能够实现表的联接,但不够明确。推荐使用显式的 JOIN 语法(如 INNER JOIN)来进行联接操作,因为它更清晰、易读,并且可以更明确地表达查询的意图,例如:

sql 复制代码
SELECT *
FROM TableA
INNER JOIN TableB ON TableA.id = TableB.id;

这种写法使用了明确的 INNER JOIN 语法来执行相同的内连接操作,更容易理解和维护。

2.3. 注意

  • 使用逗号分隔表进行表联接操作是一种较老的 SQL 写法,在现代的 SQL 标准中,更推荐使用显式的 JOIN 语法(如 INNER JOINLEFT JOIN 等),因为它们更为清晰和易读,并且能够明确表达查询的意图。
  • 显式使用 JOIN 语法(例如 INNER JOIN)能够提高代码的可读性,同时也更容易理解和维护。

3.子查询

子查询是指在 SQL 查询中嵌套的另一个查询。它允许在一个 SQL 查询中使用另一个查询的结果集作为条件或数据源。子查询可以嵌套在 SELECTINSERTUPDATEDELETE 语句的各个部分中,用于执行特定的子任务或过滤条件。

子查询通常用于以下场景:

  1. WHERE 子句中的子查询:作为过滤条件使用。
sql 复制代码
SELECT column1, column2
FROM table1
WHERE column1 = (SELECT column1 FROM table2 WHERE condition);
  1. FROM 子句中的子查询:作为数据源使用。
sql 复制代码
SELECT column1, column2
FROM (SELECT column1, column2 FROM table1) AS subquery;
  1. 在 INSERT 语句中的子查询:用于从另一个表中选择数据插入到目标表中。
sql 复制代码
INSERT INTO table1 (column1, column2)
SELECT column1, column2
FROM table2
WHERE condition;
  1. 在 UPDATE 语句中的子查询:用于根据另一个查询的结果更新数据。
sql 复制代码
UPDATE table1
SET column1 = (SELECT column1 FROM table2 WHERE condition)
WHERE condition;

子查询可以是标量子查询(返回单个值)、行子查询(返回一行结果集)或表子查询(返回多行结果集)。它们提供了更灵活的方式来构建复杂的查询,可以根据需要嵌套多个层级的子查询。

尽管子查询功能强大,但过多或复杂的嵌套子查询可能会降低查询性能。因此,在使用子查询时,需要谨慎选择合适的条件和结构,并进行必要的优化以确保查询的效率和性能。

相关推荐
Ai 编码助手2 小时前
MySQL中distinct与group by之间的性能进行比较
数据库·mysql
陈燚_重生之又为程序员2 小时前
基于梧桐数据库的实时数据分析解决方案
数据库·数据挖掘·数据分析
caridle3 小时前
教程:使用 InterBase Express 访问数据库(五):TIBTransaction
java·数据库·express
白云如幻3 小时前
MySQL排序查询
数据库·mysql
萧鼎3 小时前
Python并发编程库:Asyncio的异步编程实战
开发语言·数据库·python·异步
^velpro^3 小时前
数据库连接池的创建
java·开发语言·数据库
荒川之神3 小时前
ORACLE _11G_R2_ASM 常用命令
数据库·oracle
IT培训中心-竺老师3 小时前
Oracle 23AI创建示例库
数据库·oracle
小白学大数据3 小时前
JavaScript重定向对网络爬虫的影响及处理
开发语言·javascript·数据库·爬虫