SQL中的CROSS JOIN与INNER JOIN

Posted

技术标签:

【中文标题】SQL中的CROSS JOIN与INNER JOIN【英文标题】:CROSS JOIN vs INNER JOIN in SQL 【发布时间】:2013-07-19 13:00:12 【问题描述】:

CROSS JOININNER JOIN 有什么区别?

交叉连接:

SELECT 
    Movies.CustomerID, Movies.Movie, Customers.Age, 
    Customers.Gender, Customers.[Education Level], 
    Customers.[Internet Connection], Customers.[Marital Status], 
FROM   
    Customers 
CROSS JOIN 
    Movies

内连接:

SELECT 
    Movies.CustomerID, Movies.Movie, Customers.Age, 
    Customers.Gender, Customers.[Education Level], 
    Customers.[Internet Connection], Customers.[Marital Status]
FROM   
    Customers 
INNER JOIN 
    Movies ON Customers.CustomerID = Movies.CustomerID

哪个更好,我为什么要使用其中一个?

【问题讨论】:

CROSS JOIN 将产生所有可能的表格组合。例如100 行的 Table1 和 100 行的 Table2 将产生 10000 条记录。 x CROSS JOIN yx INNER JOIN y ON 1=1 【参考方案1】:

CROSS JOIN = (INNER) JOIN = 逗号 (",")

TL;DR SQL CROSS JOIN、(INNER) JOIN 和逗号 (",") 之间的唯一区别(除了逗号对于评估顺序的优先级较低)是 (INNER) JOIN 有一个开启,而 CROSS JOIN 和逗号不开启。


再中间产品

这三个都产生了一个中间概念 SQL 风格的关系“笛卡尔”乘积,也就是交叉连接,它包含每个表中一行的所有可能组合。减少行数的是 ON 和/或 WHERE。 SQL Fiddle

SQL 标准定义 via product (7.5 1.b.ii), aka CROSS JOIN via (7.7 1.a) and (INNER) JOIN ON via plus WHERE (7.7 1.b).

正如***所说:

Cross join CROSS JOIN 返回连接中表的行的笛卡尔积。换句话说,它将生成将第一个表中的每一行与第二个表中的每一行组合在一起的行。

Inner join [...] 连接的结果可以定义为首先取表中所有记录的笛卡尔积(或交叉连接)(将表 A 中的每条记录与表 B 中的每条记录相结合)然后返回的结果所有满足连接谓词的记录。

“隐式连接表示法”只是在 SELECT 语句的 FROM 子句中列出要连接的表,并使用逗号分隔它们。因此它指定了一个交叉连接

Re OUTER JOIN 看我的回答 What is the difference between “INNER JOIN” and “OUTER JOIN”?.

Re OUTER JOINs 并在其中使用 ON vs WHERE 看看我的答案 Conditions in LEFT JOIN (OUTER JOIN) vs INNER JOIN.

为什么要比较表之间的列?

当没有重复行时:

每个表都包含从某个填充 [named-]blanks 语句模板中做出真实语句的行。 (它从--满足--某个(特征)谓词提出了一个真正的命题。)

基表包含从某些 DBA 给定的语句模板中做出正确语句的行:

  /* rows where
  customer C.CustomerID has age C.Age and ...
  */
  FROM Customers C

连接的中间产品包含根据其操作数模板的 AND 构成真正语句的行:

  /* rows where
      customer C.CustomerID has age C.Age and ...
  AND movie M.Movie is rented by customer M.CustomerID and ...
  */
  FROM Customers C CROSS JOIN Movies M

ON 和 WHERE 条件被与以提供进一步的模板。该值再次是满足该模板的行:

  /* rows where
      customer C.CustomerID has age C.Age and ...
  AND movie M.Movie is rented by customer M.CustomerID and ...
  AND C.CustomerID = M.CustomerID
  AND C.Age >= M.[Minimum Age]
  AND C.Age = 18
  */
  FROM Customers C INNER JOIN Movies M
  ON C.CustomerID = M.CustomerID
  AND C.Age >= M.[Minimum Age]
  WHERE C.Age = 18

特别是,比较表之间 (SQL) 相等的列意味着从产品中保留的来自连接表的模板部分的行对于这些列具有相同的(非 NULL)值。巧合的是,很多行通常会通过表之间的相等比较而被删除 - 必要且足够的是表征您想要的行。

只需为您想要的行的模板编写 SQL!

查询的含义(以及表与条件)参见:How to get matching data from another SQL table for two different columns: Inner Join and/or Union?Is there any rule of thumb to construct SQL query from a human-readable description?

重载“交叉连接”

不幸的是,“交叉连接”这个词被用于:

中间产品。 交叉连接。 (INNER) 使用 ON 或 WHERE 连接,不会将一个表中的任何列与另一个表的任何列进行比较。 (因为这往往会返回很多中间产品行。)

这些不同的含义被混淆了。 (例如这里的其他答案和 cmets。)

使用 CROSS JOIN vs (INNER) JOIN vs 逗号

常见的约定是:

当且仅当您不比较表之间的列时才使用 CROSS JOIN。那是为了表明缺乏比较是故意的。 当且仅当您比较表之间的列时,使用 (INNER) JOIN 和 ON。 (可能还有其他条件。) 不要使用逗号。

通常情况下,不在成对表上的条件也会保留在 WHERE 中。但是可能必须将它们放入 (n INNER) JOIN ON 中才能为 RIGHT、LEFT 或 FULL (OUTER) JOIN 的参数获取适当的行。

关于“不要使用逗号” 将逗号与显式 JOIN 混合可能会产生误导,因为逗号的优先级较低。但是考虑到中间产品在 CROSS JOIN、(INNER) JOIN 和逗号的含义中的作用,上面关于根本不使用它的约定的论点是不稳定的。 CROSS JOIN 或逗号就像在 TRUE 条件下的 (INNER) JOIN。中间产品 ON 和 WHERE 都在相应的谓词中引入了 AND。然而,也可以考虑 INNER JOIN ON ——例如,仅在找到满足 ON 条件的一对输入行时才生成输出行——但它仍然返回满足条件的交叉连接行。 ON 不得不 在 SQL 中补充逗号的唯一原因是编写 OUTER JOIN。当然,表达式应该明确其含义;但清楚的取决于事物的含义。

Re 维恩图 带有两个相交圆圈的维恩图可以说明输出行对于相同输入的 INNER、LEFT、RIGHT 和 FULL JOIN 之间的差异。而当 ON 无条件为 TRUE 时,INNER JOIN 结果与 CROSS JOIN 相同。它还可以说明 INTERSECT、UNION 和 EXCEPT 的 输入和输出行。并且当两个输入具有相同的列时,INTERSECT 结果与标准 SQL NATURAL JOIN 相同,而 EXCEPT 结果与涉及 LEFT & RIGHT JOIN 的某些习语相同。但它确实说明了 (INNER) JOIN 通常是如何工作的。这只是乍一看似乎是合理的。对于 ON、PK(主键)、FK(外键)和/或 SELECT 的特殊情况,它可以识别输入和/或输出的部分。您所要做的就是确定圆圈所代表的集合的元素究竟是什么。 (混乱的演示永远不会说清楚。)请记住,通常对于连接输出行与输入行具有不同的标题。而且 SQL 表是 bags 而不是 setswith NULLs

【讨论】:

“中间概念 SQL 风格的笛卡尔叉积”——这是另一种说法,“它实际上不是一组有序对,但我不能避免说‘笛卡尔积’”? :) 作为一个非数学家,我遇到过“笛卡尔积”一词的唯一上下文是有人在解释 SQL 的CROSS JOIN。我确实想知道已经熟悉笛卡尔积但无法弄清楚 CROSS JOIN 的 SQL 的频率。 @onedaywhen 运算符笛卡尔积在给定一些集合的情况下返回一组有序元组。结果是 a 笛卡尔积。对于唤起不是笛卡尔积的运算符,关系和SQL文化可悲地滥用/重载“笛卡尔积”。例如***!我反对——它只会误导/混淆。然而不幸的是,在这里我只是用我自己的话模糊地描述了 SQL 交叉连接的工作原理,并遵从 Wikipedia。我标记结果“中间概念SQL风格的笛卡尔叉积”。是的,“笛卡尔”是为那些使用/期待它的人准备的。【参考方案2】:

交叉连接

AThe CROSS JOIN 用于生成笛卡尔积。

笛卡尔积采用两组 A 和 B,并从两组给定数据生成对记录的所有可能排列。

例如,假设您有以下rankssuits 数据库表:

ranks 有以下几行:

| name  | symbol | rank_value |
|-------|--------|------------|
| Ace   | A      | 14         |
| King  | K      | 13         |
| Queen | Q      | 12         |
| Jack  | J      | 11         |
| Ten   | 10     | 10         |
| Nine  | 9      |  9         |

虽然suits 表包含以下记录:

| name    | symbol |
|---------|--------|
| Club    | ♣      |
| Diamond | ♦      |
| Heart   | ♥      |
| Spade   | ♠      |

像下面这样的 CROSS JOIN 查询:

SELECT
   r.symbol AS card_rank,
   s.symbol AS card_suit
FROM
   ranks r
CROSS JOIN
   suits s

将生成rankssuites 对的所有可能排列:

| card_rank | card_suit |
|-----------|-----------|
| A         | ♣         |
| A         | ♦         |
| A         | ♥         |
| A         | ♠         |
| K         | ♣         |
| K         | ♦         |
| K         | ♥         |
| K         | ♠         |
| Q         | ♣         |
| Q         | ♦         |
| Q         | ♥         |
| Q         | ♠         |
| J         | ♣         |
| J         | ♦         |
| J         | ♥         |
| J         | ♠         |
| 10        | ♣         |
| 10        | ♦         |
| 10        | ♥         |
| 10        | ♠         |
| 9         | ♣         |
| 9         | ♦         |
| 9         | ♥         |
| 9         | ♠         |

内连接

另一方面,INNER JOIN 不返回两个连接数据集的笛卡尔积。

相反,INNER JOIN 从左侧表中获取所有元素并将它们与右侧表中的记录进行匹配,以便:

如果右侧表没有匹配到记录,则从结果集中过滤掉左侧行 对于右侧表中的任何匹配记录,左侧行会重复,就好像该记录与右侧表上所有关联的子记录之间存在笛卡尔积一样。

例如,假设父表 post 和子表 post_comment 之间存在一对多表关系,如下所示:

现在,如果post 表有以下记录:

| id | title     |
|----|-----------|
| 1  | Java      |
| 2  | Hibernate |
| 3  | JPA       |

post_comments 表有这些行:

| id | review    | post_id |
|----|-----------|---------|
| 1  | Good      | 1       |
| 2  | Excellent | 1       |
| 3  | Awesome   | 2       |

类似于以下的 INNER JOIN 查询:

SELECT
   p.id AS post_id,
   p.title AS post_title,
   pc.review  AS review
FROM post p
INNER JOIN post_comment pc ON pc.post_id = p.id

将包含所有 post 记录及其所有关联的 post_comments

| post_id | post_title | review    |
|---------|------------|-----------|
| 1       | Java       | Good      |
| 1       | Java       | Excellent |
| 2       | Hibernate  | Awesome   |

基本上,您可以将INNER JOIN 视为过滤后的 CROSS JOIN,其中仅将匹配的记录保留在最终结果集中。

【讨论】:

“INNER JOIN 不返回两个连接数据集的笛卡尔积”当 x INNER JOIN y on 1=1 确实返回它时有点多。当您继续尝试说的内容实际上(当然)在条件 1=1 时返回它时,“相反”也是如此。除了项目符号中的语言没有清楚地描述内部连接的结果。描述它的是它是一个不满足条件的交叉连接较少的行。同样,您使用“组合”的交叉连接语言也不清楚。 @Vlad Mihalcea 内连接确实只是一个交叉连接 + where 子句。您必须通过计算所有行组合来测试匹配,这意味着您只是在逐步计算笛卡尔积,同时丢弃不匹配的行对。【参考方案3】:

这取决于您期望的输出。

交叉连接将一个表中的所有行与另一个表中的所有行匹配。内连接匹配一个或多个字段。如果您有一个有 10 行的表和另一个有 10 行的表,那么这两个连接的行为会有所不同。

交叉连接将返回 100 行并且它们不会相关,这就是所谓的笛卡尔积。内连接将记录彼此匹配。假设一个有一个主键,另一个是外键,你会得到 10 行返回。

交叉连接的通用性有限,但它的存在是为了完整性,它描述了连接表的结果,而没有向查询中添加任何关系。您可以使用交叉连接来制作单词组合或类似内容的列表。另一方面,内连接是最常见的连接。

【讨论】:

【参考方案4】:

这是 Cross Join 和 Inner Join 的最佳示例。

考虑以下表格

表格:Teacher

x------------------------x
| TchrId   | TeacherName | 
x----------|-------------x
|    T1    |    Mary     |
|    T2    |    Jim      |
x------------------------x

表格:Student

x--------------------------------------x
|  StudId  |    TchrId   | StudentName | 
x----------|-------------|-------------x            
|    S1    |     T1      |    Vineeth  |
|    S2    |     T1      |    Unni     |
x--------------------------------------x

1。内连接

内连接选择同时满足表的行。 考虑我们需要找到担任班主任的老师及其对应的学生。在这种情况下,我们需要申请JOININNER JOIN 并会

查询

SELECT T.TchrId,T.TeacherName,S.StudentName 
FROM #Teacher T
INNER JOIN #Student S ON T.TchrId = S.TchrId
SQL FIDDLE

结果

x--------------------------------------x
|  TchrId  | TeacherName | StudentName | 
x----------|-------------|-------------x            
|    T1    |     Mary    |    Vineeth  |
|    T1    |     Mary    |    Unni     |
x--------------------------------------x

2。交叉连接

交叉连接选择第一个表中的所有行和第二个表中的所有行,并显示为笛卡尔积,即,具有所有可能性 考虑到我们需要找到学校里所有的老师和学生,不管班主任是谁,我们需要申请CROSS JOIN

查询

SELECT T.TchrId,T.TeacherName,S.StudentName 
FROM #Teacher T
CROSS JOIN #Student S 
SQL FIDDLE

结果

x--------------------------------------x
|  TchrId  | TeacherName | StudentName | 
x----------|-------------|-------------x            
|    T2    |     Jim     |    Vineeth  |
|    T2    |     Jim     |    Unni     |
|    T1    |     Mary    |    Vineeth  |
|    T1    |     Mary    |    Unni     |
x--------------------------------------x

【讨论】:

图 2 的键很复杂:它包围了 CROSS JOIN 参数的(颜色无关)元素,数字(无关值)是它的一行,一行(颜色无关)是结果行.对于作为袋子的表,它不是维恩图:对于作为值的行,它是错误的;对于作为元素的行,它们不能被共享。对于作为集合的表,您不需要 维恩图。图 1 是解释 JOIN 的常见可怕尝试。它的关键也很复杂:它只适用于作为集合的表&只有等值连接&只有一个值;它还表示与输出不同的输入。为 JOIN 一般写 it 图 1 作为相交圆形维恩图的 4 种颜色中的第一种是有用且正确的:(INNER)JOIN vs LEFT、RIGHT & FULL(OUTER)JOIN 但 not vs CROSS JOIN。交叉行在 JOIN 中,左/右行是 LEFT/RIGHT JOIN 中的额外(空扩展)行。它包括 CROSS JOIN 作为(INNER)JOIN 的一种特殊情况,其中非交集中没有行。 感谢您的建议。无论如何,OP已经要求这两个连接之间的区别。我以这样一种方式回答了这个问题,任何初学者都可以很容易地理解它们之间的区别。正如你所说,我没有像在生产环境中那样给出密钥。它只是一个易于理解的示例。对于Cross Join,您认为除非给出Where 子句,否则它不会返回所有行?从你的cmets来看,初学者有更多的机会感到困惑!!! @philipxy 我的 cmets 指出,这些图表很难解释,即使人们知道他们想要表达什么并且不适合这个主题。通过“关键”(图 2 或 1)我的意思是“解释图表各部分的含义”。通过“写它”,我的意思是尝试让自己非常清楚地写出图表各部分的含义。您会发现图表很复杂,并且没有演示交叉连接与内部连接!即他们不属于你的答案。 PS 表关系键在解释 JOIN 的作用方面没有任何作用。 PPS 连接之间的唯一区别是 INNER JOIN 有一个 ON。 查看 W3Schools w3schools.com/sql/sql_join_inner.asp,在那里他们为 INNER JOIN 提供了类似类型的图表。在你制作 cmets @philipxy 之前确保你是对的【参考方案5】:

交叉连接和内连接是相同的,唯一的区别是内连接我们布尔过滤了笛卡尔积的一些结果

table1
x--------------------------------------x
|  fieldA  |    fieldB   |    fieldC   | 
x----------|-------------|-------------x            
|    A     |      B      |    option1  |
|    A     |      B1     |    option2  |
x--------------------------------------x

table2
x--------------------------------------x
|  fieldA  |    fieldB   |    fieldC   | 
x----------|-------------|-------------x            
|    A     |      B      |    optionB1 |
|    A1    |      B1     |    optionB2 |
x--------------------------------------x

 cross join
  A,B,option1,A,B,optionB1
  A,B,option1,A1,B1,optionB2
  A,B1,option2,A,B,optionB1
  A,B1,option2,A1,B1,optionB2

 inner join on field1 (only with the value is the same in both tables)
  A,B,option1,A,B,optionB1
  A,B1,option2,A,B,optionB1

 inner join on field1
  A,B,option1,A,B,optionB1

在我们的数据设计中,我们决定只有一种我们用于连接的字段的情况。 Join only cross join 两个表,只获取完成特殊布尔表达式的行。

请注意,如果我们正在执行联接的字段在两个表中都为空,我们将通过过滤器。由我们或数据库制造商决定是否添加额外的规则来避免或允许空值。坚持基本原则,它只是一个交叉连接,然后是一个过滤器。

【讨论】:

【参考方案6】:

内连接将给出两个表之间匹配记录的结果,而交叉连接则为您提供两个表之间可能的组合。

【讨论】:

【参考方案7】:

SQL Server 也接受以下更简单的表示法:

SELECT A.F, 
       B.G, 
       C.H 
  FROM TABLE_A A, 
       TABLE_B B, 
       TABLE_C C
 WHERE A.X = B.X 
   AND B.Y = C.Y

使用这种更简单的表示法,您无需担心内部连接和交叉连接之间的区别。代替两个“ON”子句,有一个“WHERE”子句可以完成这项工作。如果您在确定哪些“JOIN”“ON”子句的位置有任何困难,请放弃“JOIN”符号并使用上面更简单的符号。

这不是作弊。

【讨论】:

【参考方案8】:

内连接

仅显示两个连接表中匹配的行的连接称为内连接。这是查询和视图设计器中的默认连接。

内连接语法

SELECT t1.column_name,t2.column_name
FROM table_name1 t1
INNER JOIN table_name2 t2
ON t1.column_name=t2.column_name

交叉连接

一种交叉连接,它产生参与连接的表的笛卡尔积。笛卡尔积的大小是第一个表中的行数乘以第二个表中的行数。

交叉连接的语法

SELECT * FROM table_name1
CROSS JOIN table_name2

或者我们也可以用另一种方式来写

SELECT * FROM table_name1,table_name2

现在检查下面的交叉连接查询

例子

SELECT * FROM UserDetails
CROSS JOIN OrderDetails

或者

SELECT * FROM UserDetails, OrderDetails

【讨论】:

【参考方案9】:

请记住,如果添加了 WHERE 子句,则交叉连接表现为内连接。例如,以下 Transact-SQL 查询产生相同的结果集。请参考http://technet.microsoft.com/en-us/library/ms190690(v=sql.105).aspx

【讨论】:

【参考方案10】:

在使用内连接编写查询时,如果两个表都满足条件,即两个表中的公共列完全匹配,则将从两个表中获取记录。

使用交叉连接编写查询时,结果类似于两个表中记录数的笛卡尔积。例如,如果 table1 包含 2 条记录,table2 包含 3 条记录,则查询结果为 2*3 = 6 条记录。

所以在需要之前不要进行交叉连接。

【讨论】:

仅当缺少 WHERE 子句时!【参考方案11】:

交叉连接不合并行,如果每个表有 100 行,1 对 1 匹配,则得到 10.000 个结果,Innerjoin 在相同情况下只会返回 100 行。

这 2 个示例将返回相同的结果:

交叉连接

select * from table1 cross join table2 where table1.id = table2.fk_id

内联

select * from table1 join table2 on table1.id = table2.fk_id

使用最后一种方法

【讨论】:

我相信你可以将select * from table1 cross join table2 where table1.id = table2.fk_id写成select * from table1, table2 where table1.id = table2.fk_id(用cross join替换, @Lucas 这是连接的旧语法,但它会起作用。不过我推荐 Clausen 的版本,可读性更强。 1对1匹配是什么意思? “同样的情况”是什么意思 @iliketocode "old syntax for joins" 不清楚,你最好说说SQL-89和SQL-92标准 你的 INNER JOIN "100" 是一个特殊情况,你没有解释过,你没有解释过一般情况。

以上是关于SQL中的CROSS JOIN与INNER JOIN的主要内容,如果未能解决你的问题,请参考以下文章

SQL中inner join,outer join和cross join的区别

SQL中的JOIN类型解释(CROSS, INNER,OUTER),关键字ON,USING

关于SQL数据库中cross join 和inner join用法上的区别?

MySQL中inner join 和 cross join 的区别

sql JOINs - JOIN,INNER JOIN,LEFT JOIN,RIGHT JOIN,CROSS JOIN

SQL中inner join,outer join和cross join的区别