交叉连接的用途是什么?

118

交叉连接在两组元组上执行笛卡尔积操作。

SELECT *
FROM Table1
CROSS JOIN Table2
哪些情况会使得这样的SQL操作特别有用?

50
很遗憾这个问题被关闭了。我认为它可以被标记为社区维基,但说它不具有建设性是不公平的。 - Wayne Koorts
13
有时候新手开发者在使用软件时会难以理解某些函数的含义。像这样的问题对于新手开发者来说特别有帮助,主要是因为其后的讨论可以阐明很多初级开发者从未考虑过的可能性。该问题的格式最多只能算基础入门级别,但它的意图似乎很真诚,即询问“这个存在的意义是什么?”我同意Wayne Koorts的观点,很遗憾casperOne选择关闭此问题并称其为“没有建设性”。尤其是“没有建设性”这部分让我感到非常恼火。 - Kaorie
SQL中的CROSS JOIN和INNER JOIN的区别 - philipxy
9个回答

109
如果您有一个需要完全填充的“网格”,例如针对特定服装款式的尺寸和颜色信息:
select 
    size,
    color
from
    sizes CROSS JOIN colors

也许您需要一张包含每天每分钟的行的表格,并且您想要用它来验证每分钟是否执行了一个过程,因此您可能会交叉三个表:
select
    hour,
    minute
from
    hours CROSS JOIN minutes

或者你有一组标准报告规范,想要将其应用到每个月份:
select
    specId,
    month
from
    reports CROSS JOIN months

将这些内容作为视图进行维护的问题在于,在大多数情况下,你不需要一个完整的产品,特别是对于服装而言。您可以向查询中添加MINUS逻辑以删除您不包含的某些组合,但您可能会发现通过其他方式填充表格并不使用笛卡尔积更容易。

此外,您可能会尝试对具有比您预想的更多行的表进行交叉联接,或者您的WHERE子句部分或全部缺失。在这种情况下,您的数据库管理员会迅速通知您有遗漏。通常他或她不会很高兴。


5
如果出现这种情况,你的数据库管理员会立即通知你有遗漏。通常他或她不会很高兴。哈哈,太真实了! - RSW
2
@Dave:第二个例子不是只有小时CROSS JOIN分钟吗? - Rakesh
@Rakesh,干得好,我当时想的是其他事情,跟我打字的不一样。已经修复了。 - Dave DuPlantis
1
我可以想象如果你有两组ID(可能是CSV格式),一组包含员工ID,另一组包含任务ID,那么交叉连接会非常实用。这个想法是你有一个EmployeeTask的M2M表。你可以使用交叉连接将每个给定的任务分配给每个给定的员工,前提是你将CSV转换为表变量(或其他东西)。 - SynBiotik

32

生成测试数据。


3
我从未想过一个四个字的“答案”会得到九个赞。 - mickmackusa
2
现在你有一个更好的选择:https://generatedata.com/。 - user1124825

15

对于大多数数据库查询,您通常不需要完整的笛卡尔积。关系型数据库的全部优势在于您可以应用任何限制,以使您避免从数据库中提取不必要的行。

我想一个牵强的例子可能是,如果您有一个员工表和一个需要执行的作业表,并希望查看一个员工分配到一个作业的所有可能性。


14

好的,这可能不会回答问题,但如果确实如此(我甚至不确定),它是一个有趣的历史片段。

在Oracle早期,一个开发人员意识到他需要复制表中的每一行(例如,可能是一个事件表,他需要将其分为“开始事件”和“结束事件”条目)。 他意识到,如果他有一个只有两行的表,他可以做一个交叉连接,在第一个表中选择只有列,并得到他所需要的。 因此,他创建了一个简单的表格,自然而然地称为“DUAL”。

后来,他需要做一些只能通过从表格中选择进行的操作,即使该操作本身与表格无关,(也许他忘记了手表,想通过SELECT SYSDATE FROM ...读取时间) 他意识到他仍然有他的DUAL表格,于是使用了它。 过了一会儿,他厌倦了时间被打印两次的情况,所以最终删除了其中的一行。

Oracle的其他人开始使用他的表格,最终决定将其包含在标准Oracle安装程序中。

这就解释了为什么一个唯一重要性是它只有一行的表格具有“两个”的含义的名称。


13

关键是“显示所有可能的组合”。 我已经将它们与其他计算字段结合使用,然后对其进行排序/筛选。

例如,假设您正在构建一个套利(交易)应用程序。 您有销售者以价格提供产品,买家以成本要求产品。 您在产品密钥上执行交叉连接(以匹配潜在的买家和卖家),计算成本和价格之间的差价,然后按此降序排列,以便为您(中间商)提供最具利润的交易。 当然,几乎总会有其他边界过滤条件。


啊!这个解释对我来说最有意义了。在这种情况下,使用INNER JOIN没有意义,因为产品ID和卖家之间没有关系,因为多个卖家可以销售同一产品。 - user749127

4

拿一个数字表格举例,其中有十行对应数字0-9。你可以使用交叉连接(cross join)多次操作该表格,得到任意数量的行,每一行都有相应的编号。这有很多用途。例如,你可以与dateadd()函数结合使用,得到给定年份中每一天的集合。


注意:此帖子现在已经过时。今天我会使用 generate_series() 或递归 CTE 来完成这项工作。

2
你可以使用CROSS JOIN来:
  • 生成测试数据
  • 组合所有属性 - 比如你需要所有可能的血型(A,B,...)与Rh-/+等的组合... --根据你的需求进行调整;) - 我不是这个领域的专家;)
最初的回答
CREATE TABLE BL_GRP_01 (GR_1 text);
CREATE TABLE RH_VAL_01 (RH_VAL text);
INSERT INTO BL_GRP_01 VALUES ('A'), ('B'), ('AB'), ('O');
INSERT INTO RH_VAL_01 VALUES ('+'), ('-');

SELECT CONCAT(x.GR_1, y.RH_val)
       FROM BL_GRP_01 x
 CROSS JOIN RH_VAL_01 y
ORDER BY CONCAT(x.GR_1, y.RH_VAL);
  • 创建两个没有共同id的表的连接,然后使用max()等函数进行分组,以找到可能的最高组合。

注:Original Answer翻译成"最初的回答"


2
这是一种有趣的使用交叉连接创建交叉表报告的方法。我在《Joe Celko's SQL For Smarties》一书中发现了它,并已多次使用。它需要一些设置,但投入的时间是值得的。

1
假设您有一系列查询需要针对特定商品和日期(价格、可用性等)发出。 您可以将商品和日期加载到单独的临时表中,并使您的查询交叉连接这些表。 这可能比枚举IN子句中的商品和日期更方便,特别是由于某些数据库限制了IN子句中元素的数量。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接