Quais são os usos do Cross Join?

105

Uma junção cruzada executa um produto cartesiano nas tuplas dos dois conjuntos.

SELECT *
FROM Table1
CROSS JOIN Table2

Quais circunstâncias tornam essa operação SQL particularmente útil?

Llyle
fonte
36
É muito triste que esta questão tenha sido encerrada. Eu acho que poderia ser marcado como Community Wiki, mas dizer que não é construtivo é injusto.
Wayne Koorts
1
Concordo. Isso respondeu exatamente à minha pergunta.
Hades
10
Há momentos em que um desenvolvedor mais recente tem problemas para entender as implicações de certas funções do software que está usando. Perguntas como essa são particularmente úteis para desenvolvedores mais novos, principalmente porque a discussão a seguir ilumina muitas possibilidades que o desenvolvedor júnior nunca considerou. O formato da pergunta é elementar, na melhor das hipóteses, mas a intenção parece ser honesta na medida em que pergunta "por que isso existe?" Eu concordo com Wayne Koorts, é uma pena que casperOne tenha optado por encerrar isso e chamado de "não construtivo". A parte "não construtiva" me irrita particularmente.
Kaorie,

Respostas:

93

Se você tiver uma "grade" que deseja preencher completamente, como informações de tamanho e cor de uma determinada peça de roupa:

select 
    size,
    color
from
    sizes CROSS JOIN colors

Talvez você queira uma tabela que contenha uma linha para cada minuto do dia e queira usá-la para verificar se um procedimento foi executado a cada minuto, então você pode cruzar três tabelas:

select
    hour,
    minute
from
    hours CROSS JOIN minutes

Ou você tem um conjunto de especificações de relatório padrão que deseja aplicar a todos os meses do ano:

select
    specId,
    month
from
    reports CROSS JOIN months

O problema em mantê-los como visualizações é que, na maioria dos casos, você não quer um produto completo, principalmente no que diz respeito a roupas. Você pode adicionar MINUSlógica à consulta para remover certas combinações que você não carrega, mas você pode achar mais fácil preencher uma tabela de outra forma e não usar um produto cartesiano.

Além disso, você pode acabar tentando a junção cruzada em tabelas que talvez tenham mais algumas linhas do que você pensava ou talvez sua WHEREcláusula esteja parcial ou totalmente ausente. Nesse caso, seu DBA irá notificá-lo imediatamente sobre a omissão. Normalmente, ele ou ela não ficará feliz.

Dave DuPlantis
fonte
5
... Nesse caso, seu DBA irá notificá-lo imediatamente sobre a omissão. Normalmente, ele ou ela não ficará feliz. ... haha, é verdade!
RSW
2
@Dave: O segundo exemplo não terá apenas hora CROSS JOIN minutos?
Rakesh de
@Rakesh, bom apanhado, estava pensando em algo diferente do que estava digitando. Fixo.
Dave DuPlantis
1
Posso imaginar uma junção cruzada muito prática se você recebesse 2 conjuntos de ids (talvez no formato csv), um conjunto conteria os ids dos funcionários e o outro conteria os ids das tarefas. A ideia é que você tenha uma tabela M2M para EmployeeTask. Você poderia usar a junção cruzada para atribuir cada tarefa a cada funcionário, desde que tenha transformado o csv em variáveis ​​de tabela (ou algo assim).
SynBiotik
20

Gere dados para teste.

Ovidiu Pacurar
fonte
Nunca pensei que veria uma "resposta" de 4 palavras receber 9 votos positivos.
mickmackusa,
14

Normalmente, você não vai querer um produto cartesiano completo para a maioria das consultas de banco de dados. Todo o poder dos bancos de dados relacionais é que você pode aplicar quaisquer restrições nas quais possa estar interessado para evitar a extração de linhas desnecessárias do banco de dados.

Suponho que um exemplo inventado em que você pode querer isso é se você tem uma tabela de funcionários e uma tabela de trabalhos que precisam ser feitos e deseja ver todas as atribuições possíveis de um funcionário para um trabalho.

Randy
fonte
11

Ok, isso provavelmente não vai responder à pergunta, mas, se for verdade (e eu nem tenho certeza disso), é um bocado divertido de história.

Nos primeiros dias da Oracle, um dos desenvolvedores percebeu que precisava duplicar todas as linhas de uma tabela (por exemplo, é possível que fosse uma tabela de eventos e ele precisou alterá-la separadamente "evento inicial" e "evento final" entradas). Ele percebeu que se tivesse uma tabela com apenas duas linhas, ele poderia fazer uma junção cruzada, selecionando apenas as colunas na primeira tabela, e obter exatamente o que precisava. Então ele criou uma mesa simples, que ele chamou naturalmente de "DUAL".

Mais tarde, ele precisa fazer algo que só poderia ser feito por meio de um select de uma tabela, embora a ação em si não tivesse nada a ver com a tabela (talvez ele tenha esquecido o relógio e quisesse ler a hora via SELECT SYSDATE FROM .. .) Ele percebeu que ainda tinha sua mesa DUAL ao redor e a usou. Depois de um tempo, ele se cansou de ver a hora impressa duas vezes, então acabou apagando uma das linhas.

Outros na Oracle começaram a usar sua tabela e, eventualmente, decidiu-se incluí-la na instalação padrão do Oracle.

O que explica por que uma tabela cujo único significado é ter uma linha tem um nome que significa "dois".

James Curran
fonte
8

A chave é "mostre-me todas as combinações possíveis". Usei-os em conjunto com outros campos calculados e os classifiquei / filtrou.

Por exemplo, digamos que você esteja criando um aplicativo de arbitragem (negociação). Você tem vendedores oferecendo produtos a um preço e compradores pedindo produtos a um custo. Você faz uma junção cruzada na chave do produto (para combinar os compradores e vendedores em potencial), calcula a diferença entre custo e preço e classifica desc. sobre isso para dar a você (o intermediário) as negociações mais lucrativas para executar. Quase sempre você terá outros critérios de filtro delimitadores, é claro.

Kevin Dostalek
fonte
Ah! Essa explicação faz mais sentido para mim. Nesse caso, um INNER JOIN não faz sentido porque não há relação entre um ID de produto e um vendedor, já que vários vendedores podem vender o mesmo produto.
moonman239
3

É algo como uma tabela de dígitos, que possui dez linhas para os dígitos de 0 a 9. Você pode usar a junção cruzada nessa tabela algumas vezes para obter um resultado que tenha quantas linhas forem necessárias, com os resultados numerados apropriadamente. Isso tem vários usos. Por exemplo, você pode combiná-lo com uma função datadd () para obter um conjunto para todos os dias de um determinado ano.

Joel Coehoorn
fonte
1

Imagine que você tenha uma série de consultas que deseja fazer sobre uma combinação específica de itens e datas (preços, disponibilidade, etc.). Você pode carregar os itens e as datas em tabelas temporárias separadas e fazer com que suas consultas se juntem às tabelas. Isso pode ser mais conveniente do que a alternativa de enumerar os itens e datas nas cláusulas IN, especialmente porque alguns bancos de dados limitam o número de elementos em uma cláusula IN.

completamente
fonte
1

você pode usá-lo CROSS JOIN para: - gerar dados para fins de teste - combinar todas as propriedades - você precisa de todas as combinações possíveis de, por exemplo, grupos sanguíneos (A, B, ..) com Rh - / +, etc ... --tune-o para seus propósitos;) - Não sou especialista nesta área;)

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;
  • crie uma junção para 2 tabelas sem um id comum e então agrupe usando max (), etc. para encontrar a combinação mais alta possível
HankerPL
fonte