交叉联接有什么用?


105

交叉联接在两个集合的元组上执行笛卡尔乘积。

SELECT *
FROM Table1
CROSS JOIN Table2

哪些情况下此类SQL操作特别有用?


36
对于这个问题已经解决感到非常遗憾。我认为可以将其标记为Community Wiki,但是说它不具有建设性是不公平的。
韦恩·考特斯

1
我同意。这回答了我的确切问题。
哈德斯

10
有时,新手开发人员难以理解他们正在使用的软件某些功能的含义。诸如此类的问题对新开发人员特别有用,主要是因为随后的讨论阐明了初级开发人员从未考虑过的许多可能性。问题的形式充其量只是最基本的问题,但其目的似乎是诚实的,因为它询问“为什么甚至存在?” 我同意韦恩·科特斯(Wayne Koorts)的观点,casperOne选择关闭此方法并称其“无建设性”,这是一种耻辱。“非建设性”部分尤其让我感到讨厌。
Kaorie

Answers:


93

如果您要完全填充“网格”,例如特定服装的尺寸和颜色信息,请执行以下操作:

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子句部分或完全丢失。在这种情况下,您的DBA会立即将您的遗漏通知您。通常他或她不会幸福。


5
...在这种情况下,您的DBA会立即将您的遗漏通知您。通常他或她不会幸福。...哈哈,如此真实!
RSW

2
@Dave:第二个例子不是CROSS JOIN分钟吗?
Rakesh

@Rakesh,很好,我在想的不是输入的内容。固定。
Dave DuPlantis

1
我可以想象,如果为您提供2套ID(也许采用csv格式),则交叉连接非常实用,其中一组将包含员工ID,而另一组将包含任务ID。这个想法是您有一个EmployeeTask的M2M表。您可以使用交叉联接将每个给定的任务分配给每个给定的雇员,前提是您将csv转换为表变量(或其他变量)。
SynBiotik 2014年


14

通常,大多数数据库查询都不需要完整的笛卡尔积。关系数据库的全部功能是您可以应用可能感兴趣的任何限制,从而避免从数据库中提取不必要的行。

我假设有一个人为设计的示例,如果您有一张雇员表和一张需要做的工作表,并且想查看一名雇员对一项工作的所有可能分配,您可能希望这样做。


11

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

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

后来,他需要做一些只能通过从表中进行选择来完成的操作,即使动作本身与表无关,(也许他忘记了手表,想通过SELECT SYSDATE FROM读取时间。 。)他意识到自己仍然还有DUAL桌子,并使用了它。一段时间后,他厌倦了看到两次打印时间,因此最终删除了其中一行。

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

这就解释了为什么一个表的唯一意义是具有一行的表的名称为何表示“两个”。


8

关键是“告诉我所有可能的组合”。我将它们与其他计算字段结合使用,然后对其进行了排序/过滤。

例如,假设您正在构建套利(交易)应用程序。您有卖家以一定价格提供产品,而买家以一定价格要求产品。您对产品密钥进行交叉联接(以匹配潜在的买方和卖方),计算成本和价格之间的价差,然后对desc进行排序。以此为您(中间人)执行最有利可图的交易。当然,几乎总是会有其他边界过滤器条件。


啊! 这种解释对我来说最有意义。在这种情况下,INNER JOIN毫无意义,因为产品ID与卖方之间没有关系,因为多个卖方可以出售同一产品。
moonman239

3

采取类似数字表的方法,其中有十行用于数字0-9。您可以在该表上多次使用交叉联接,以获得具有所需行数的get结果,并对结果进行适当编号。这有许多用途。例如,您可以将其与datadd()函数结合使用以获取给定年份中每天的集合。



1

假设您要针对商品和日期(价格,库存状况等)的特定组合进行一系列查询。您可以将项目和日期加载到单独的临时表中,并使查询交叉联接到这些表中。这可能比枚举IN子句中的项目和日期的方法更方便,尤其是因为某些数据库限制了IN子句中的元素数量。


1

您可以使用CROSS JOIN来执行以下操作:-生成用于测试目的的数据-合并所有属性-您需要使用所有可能的组合,例如血型(A,B,..)与Rh-/ +等...- 调整它为了您的目的;)-我不是这方面的专家;)

CREATE TABLE "HR"."BL_GRP_01" 
("GR_1" VARCHAR2(5 BYTE));
REM INSERTING into BL_GRP_01
SET DEFINE OFF;
Insert into BL_GRP_02 (GR_1) values ('A');
Insert into BL_GRP_02 (GR_1) values ('B');
Insert into BL_GRP_02 (GR_1) values ('O');
Insert into BL_GRP_01 (GR_1) values (NULL);

CREATE TABLE "HR"."BL_GRP_02" 
("GR_1" VARCHAR2(5 BYTE));

REM INSERTING into BL_GRP_02
SET DEFINE OFF;
Insert into BL_GRP_02 (GR_1) values ('A');
Insert into BL_GRP_02 (GR_1) values ('B');
Insert into BL_GRP_02 (GR_1) values ('O');
Insert into BL_GRP_02 (GR_1) values (NULL);

CREATE TABLE "HR"."RH_VAL_01" 
("RH_VAL" VARCHAR2(5 BYTE));
REM INSERTING into RH_VAL_01
SET DEFINE OFF;
Insert into RH_VAL_01 (RH_VAL) values ('+');
Insert into RH_VAL_01 (RH_VAL) values ('-');
Insert into RH_VAL_01 (RH_VAL) values (NULL);

select distinct  a.GR_1 || b.GR_1 || c.RH_VAL as BL_GRP
from BL_GRP_01 a, BL_GRP_02 b, RH_VAL_01 c
GROUP BY a.GR_1, b.GR_1, c.RH_VAL;
  • 为2个没有共同ID的表创建一个联接,然后使用max()等对其进行分组,以找到可能的最高组合
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.