SQL中的CROSS JOIN与INNER JOIN


150

CROSS JOIN和之间有什么区别INNER 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

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


15
CROSS JOIN将导致表格的所有可能组合。例如,具有100行的Table1和具有100行的Table2将产生10000条记录。
bummi

x CROSS JOIN yx INNER JOIN y ON 1=1
philipxy

Answers:


119

交叉联接不会合并行,如果每个表中有100行且一对一匹配,您将获得10.000个结果,Innerjoin在相同情况下将仅返回100行。

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

交叉联接

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

内部联接

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

使用最后一种方法


7
我相信你可以写select * from table1 cross join table2 where table1.id = table2.fk_idselect * from table1, table2 where table1.id = table2.fk_id(替换cross join,
modulitos

5
@Lucas是用于联接的旧语法,但是它将起作用。我建议使用Clausn的版本,使其更具可读性。
iliketocode '16

1
1对1比赛是什么意思?您是什么意思“同样的情况”
Jwan622 '18

1
@iliketocode“联接的旧语法”目前尚不清楚,您最好谈论一下SQL-89和SQL-92标准
Ivanzinho,

您的INNER JOIN“ 100”是一种特殊情况,您没有说明,也没有说明一般情况。
philipxy

186

这是交叉连接和内部连接的最佳示例。

考虑下表

表: 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

结果

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 

结果

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

1
图2的键很复杂:它将CROSS JOIN的参数的元素(与颜色无关)围起来,数字(与值无关)是它的一行,而一条线(与颜色无关)是结果行。对于作为袋的表,它不是维恩图:对于作为值的行,这是错误的;对于作为元素的行,它们不能共享。对于作为集合的表,您不需要维恩图。图1是解释JOIN 的常见可怕尝试。它的密钥也很复杂:仅用于表为集合,仅用于等值联接,并且仅用于一个值。它也代表输入而不是输出。通常为JOIN 编写
philipxy 2015年

图1有用且正确,它是相交圆维恩图的4种颜色中的第一种,它们用于:(内部)联接与左,右与全(外部)联接,但与交叉联接无关。交叉点行在JOIN中,左/右行是LEFT / RIGHT JOIN中的多余(空扩展)行。它包括 CROSS JOIN作为(INNER)JOIN的特例,其中非相交处没有行。
philipxy 2015年

1
感谢您的建议。无论如何,OP要求这两个联接之间有区别。我以任何初学者都可以轻松理解它们之间的区别的方式回答了这个问题。如您所说,我没有提供生产环境中的密钥。它只是一个易于理解的示例。对于Cross Join,您是否认为除非Where给出子句,否则它不会返回所有行?从您的评论中,有更多机会让初学者感到困惑!!!@philipxy
Sarath Avanavu 2015年

1
我的评论指出,即使人们知道他们想说的话也很难解释这些图并且不适合该主题。用“键”(图2或1)表示“对图各部分的含义的解释”。所谓“写”,是指您自己尝试清楚地写出图中各部分的含义。您会发现这些图很复杂,并且没有演示交叉联接与内部联接!也就是说,它们不属于您的答案。PS Table关系键在解释JOIN的作用方面没有作用。PPS联接之间的唯一区别是INNER JOIN的ON。
philipxy 2015年

在W3Schools w3schools.com/sql/sql_join_inner.asp中查找,他们在其中为INNER JOIN提供了类似的图表类型。发表评论@philipxy之前,请确保您是对的
Sarath Avanavu

69

CROSS JOIN =(INNER)JOIN =逗号(“,”)

TL; DR SQL CROSS JOIN,(INNER)JOIN和逗号(“,”)之间的唯一区别(除了逗号在评估顺序上具有较低的优先级)是(INNER)JOIN具有ON,而CROSS JOIN和逗号则没有。


再中间产品

这三者都产生了中间概念性SQL风格的关系“笛卡尔”乘积(又名交叉联接),每个表中一行的所有可能组合。ON和/或WHERE减少行数。SQL小提琴

SQL标准通过乘积(7.5 1.b.ii)定义 <逗号>,通过<逗号>(7.7 1.a)定义 <交叉联接>,并通过<逗号>加WHERE(7.7 1.b)联接<搜索条件>。 )。

正如维基百科所说:

交叉联接

CROSS JOIN返回联接中表的行的笛卡尔积。换句话说,它将产生将第一张表中的每一行与第二张表中的每一行合并的行。

内部联接

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

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

关于OUTER JOINs并在其中使用ON vs WHERE参见LEFT JOIN(OUTER JOIN)vs INNER JOIN中的条件

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

如果没有重复的行:

每个表都包含从特定的[[named]]空白语句模板中构成真实语句的行。(它从- 满足-某个(特征)谓词提出了真实的命题。)

  • 基本表包含从某些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
  • “与”条件在“与”条件下进行运算以提供进一步的模板。值再次是满足该模板的行:

    /* 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!

有关查询(以及表与条件)的含义,请参见:
如何从另一个SQL表中为两个不同的列获取匹配数据:内部联接和/或联合?
是否有任何经验法则可以从易于理解的描述中构造SQL查询?

重载“交叉连接”

不幸的是,术语“交叉连接”用于:

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

这些不同的含义变得混乱。(例如,此处的其他答案和评论。)

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

通用约定是:

  • 当且仅当您不比较表之间的列时,才使用CROSS JOIN。这表明缺乏比较是故意的。
  • 当且仅当在表之间比较列时,才将(INNER)JOIN与ON一起使用。(加上其他条件。)
  • 不要使用逗号。

通常,还为WHERE保留了不在一对表上的条件。但是可能必须将它们放在(n INNER)JOIN ON上,以便为RIGHT,LEFT或FULL(OUTER)JOIN的参数获取适当的行。

关于“请勿使用逗号”,因为逗号的优先级较低,所以将逗号与显式JOIN混合会误导您。但是考虑到中间产品在CROSS JOIN,(INNER)JOIN和逗号中的作用,上述不使用它的惯例的论点是不稳定的。交叉联接或逗号就像处于“ TRUE”条件的(“内部”联接)一样。中间产品ON和WHERE都会在相应谓词中引入AND。但是,还可以考虑使用INNER JOIN ON-例如,仅当找到满足ON条件的一对输入行时才生成输出行-但是它返回满足条件的交叉联接行。ON 必须在SQL中补充逗号的唯一原因是编写 OUTER联接。当然,表达应该使含义清楚;但是清楚取决于要表达的意思。

Re Venn图具有两个相交圆的Venn图可以说明同一输入的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表是与空值。)


6
+1我最喜欢这个答案-其他人似乎暗示结果会有所不同,但是如果将“ ON”子句替换为“ WHERE”,则结果是相同的
Ronnie 2015年

4
+1感谢您清理,省略INNER JOIN中的ON子句将产生与使用CROSS JOIN完全相同的结果
Cerno

“中间概念性SQL风格的笛卡尔叉积” –是另一种说法,“它实际上不是一组有序对,但我无法避免说'笛卡尔积'”?:)作为我自己的非数学家,我遇到“笛卡尔积”一词的唯一上下文是某人在解释SQL时CROSS JOIN。我确实想知道已经有人对笛卡尔积已经熟悉但又无法弄清楚的SQL的使用频率CROSS JOIN
一天,

1
@onedayw当运算符笛卡尔乘积返回给定集合的一组有序元组时。其结果是一个笛卡尔乘积。关系和SQL文化可悲地误用/重载了引起不是笛卡尔乘积的运算符。例如Wikipedia!我反对,这只是误导/混淆。但是,不幸的是,在这里我仅用自己的语言模糊地描述了SQL交叉联接的工作方式,并顺应了Wikipedia。我将结果标记为“中间概念性SQL风格的笛卡尔叉积”。是的,“笛卡尔”适用于那些已经使用/期待它的可悲的腐败者。
philipxy

1
这是正确的答案,与更高评分的答案不同。使用SQL的典型做法是,尽管无法理解或定义语言的基本知识,但浅浅,合理,格式合理的带图片的解释仍占教学内容的主导地位。
查尔斯·罗迪

23

内部联接

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

内部联接的语法

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


8

交叉加入

正如我在本文中所解释的,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将从左侧表中获取所有元素,并将其与右侧表中的记录进行匹配,从而:

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

例如,假设我们在父表和子表之间具有一对多表关系,如下所示:postpost_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工作原理的更多详细信息,请查看 本文


当1 = 1上的x INNER JOIN y返回时,“ INNER JOIN不返回两个联接数据集的笛卡尔积”。当您继续尝试说的话实际上(当然)在条件1 = 1时将其返回时,“替代”也是如此。除非项目符号中的语言不能清楚地描述内部连接的结果。真正描述它的是交叉连接,减少了不符合条件的行。同样,使用“组合”的交叉联接语言也不明确。
philipxy

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”表示法,并使用上面的更简单的表示法。

它不是作弊。


2

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

使用交叉联接编写查询时,结果就像两个表中没有记录的笛卡尔积。例如,如果table1包含2条记录,而table2包含3条记录,则查询结果为2 * 3 = 6条记录。

因此,在需要之前不要进行交叉连接。


2
仅当WHERE子句丢失时!
epitka 2014年

2

交叉联接和内部联接是相同的,唯一的不同是在内部联接中,我们通过布尔过滤笛卡尔积的某些结果

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

在数据设计上,我们决定只有一种情况用于联接。仅联接将两个表交叉联接,仅获得完成特殊布尔表达式的行。

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


0

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


0

A = {1,5,3,4,6,7,9,8} B = {2,8,5,4,3,6,9}

cross join 充当笛卡尔积A✖B = {1,2},{1,8} ...,{5,2},{5,8},{5,5} ..... {3,3} ...,{6,6} .... {8,9}并返回此长结果集。

处理时 inner join通过笛卡尔乘积完成并选择匹配对时。如果认为此有序对作为两个表的主键,并且在on子句中搜索A = B,则inner join选择{5,5},{4,4},{6,6} ,{9,9},并在与这些ID相关的select子句中返回询问的列。

如果cross join在a = b上,则结果与相同inner join。在那种情况下也要使用inner join


-1

这取决于您期望的输出。

交叉联接将一个表中的所有行与另一表中的所有行进行匹配。内部联接在一个或多个字段上匹配。如果您有一个表有10行,而另一个表有10行,则两个联接的行为将有所不同。

交叉联接将返回100行,它们将不相关,这就是所谓的笛卡尔乘积。内部联接将彼此匹配记录。假设一个具有主键,而另一个具有外键,则将返回10行。

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


不要混淆所有人。我试图缩短答案。这是最好的简短答案。
Shrikant Jadhav
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.