Dados de teste e recursos
movie_id de uma linha da tabela genres contém o valor id de uma linha da tabela movies.
Há um relacionamento muitos-para-muitos entre filmes e atores.
Esse relacionamento muitos-para-muitos é normalizado em dois relacionamentos um-para-muitos usando a tabela roles.
Cada linha da tabela roles contém os valores das colunas id da tabela movies e da tabela actors.
Tipos de junção compatíveis com o ClickHouse
INNER JOIN
INNER JOIN retorna, para cada par de linhas que correspondem às chaves de junção, os valores das colunas da linha da tabela à esquerda, combinados com os valores das colunas da linha da tabela à direita.
Se uma linha tiver mais de uma correspondência, todas elas serão retornadas (ou seja, o produto cartesiano é gerado para linhas com chaves de junção correspondentes).
Esta consulta encontra os gêneros de cada filme ao unir a tabela movies à tabela genres:
A palavra-chave
INNER pode ser omitida.INNER JOIN pode ser ampliado ou modificado com um dos seguintes tipos de junção.
(LEFT / RIGHT / FULL) OUTER JOIN
LEFT OUTER JOIN se comporta como um INNER JOIN; além disso, para linhas da tabela da esquerda sem correspondência, o ClickHouse retorna valores padrão para as colunas da tabela da direita.
Uma consulta RIGHT OUTER JOIN é semelhante e também retorna valores de linhas da tabela da direita sem correspondência, junto com valores padrão para as colunas da tabela da esquerda.
Uma consulta FULL OUTER JOIN combina LEFT e RIGHT OUTER JOIN e retorna valores de linhas sem correspondência das tabelas da esquerda e da direita, junto com valores padrão para as colunas das tabelas da direita e da esquerda, respectivamente.
O ClickHouse pode ser configurado para retornar NULL em vez de valores padrão (no entanto, por motivos de desempenho, isso é menos recomendável).
movies que não têm correspondência na tabela genres e, por isso, recebem (no momento da consulta) o valor padrão 0 para a coluna movie_id:
A palavra-chave
OUTER pode ser omitida.CROSS JOIN
CROSS JOIN produz o produto cartesiano completo das duas tabelas, sem levar em conta as chaves de junção.
Cada linha da tabela à esquerda é combinada com cada linha da tabela à direita.
A consulta a seguir, portanto, combina cada linha da tabela movies com cada linha da tabela genres:
WHERE para associar as linhas correspondentes e reproduzir o comportamento de INNER JOIN para encontrar os gêneros de cada filme:
CROSS JOIN especifica várias tabelas na cláusula FROM, separadas por vírgulas.
O ClickHouse reescreve um CROSS JOIN como um INNER JOIN se houver expressões de junção na seção WHERE da consulta.
Você pode verificar isso na consulta de exemplo por meio de EXPLAIN SYNTAX (que retorna a versão sintaticamente otimizada para a qual uma consulta é reescrita antes de ser executada):
INNER JOIN na versão da consulta CROSS JOIN otimizada sintaticamente contém a palavra-chave ALL, que foi adicionada explicitamente para preservar a semântica do produto cartesiano do CROSS JOIN mesmo quando a consulta é reescrita como um INNER JOIN, para o qual o produto cartesiano pode ser desativado.
OUTER pode ser omitida em um RIGHT OUTER JOIN, e a palavra-chave opcional ALL pode ser adicionada; portanto, você pode escrever ALL RIGHT JOIN, e tudo funcionará normalmente.
(LEFT / RIGHT) SEMI JOIN
LEFT SEMI JOIN retorna os valores das colunas de cada linha da tabela à esquerda que tenha pelo menos uma correspondência de chave de junção na tabela à direita.
Apenas a primeira correspondência encontrada é retornada (o produto cartesiano fica desativado).
Uma consulta RIGHT SEMI JOIN é semelhante e retorna valores para todas as linhas da tabela à direita com pelo menos uma correspondência na tabela à esquerda, mas apenas a primeira correspondência encontrada é retornada.
Esta consulta encontra todos os atores/atrizes que atuaram em um filme em 2023.
Observe que, com uma junção (INNER) normal, o mesmo ator/atriz apareceria mais de uma vez se tivesse mais de um papel em 2023:
(LEFT / RIGHT) ANTI JOIN
LEFT ANTI JOIN retorna os valores das colunas de todas as linhas sem correspondência da tabela à esquerda.
Da mesma forma, o RIGHT ANTI JOIN retorna os valores das colunas de todas as linhas sem correspondência da tabela à direita.
Uma formulação alternativa da consulta de exemplo anterior com junção externa é usar uma anti junção para encontrar filmes que não têm gênero no conjunto de dados:
(LEFT / RIGHT / INNER) ANY JOIN
LEFT ANY JOIN é a combinação de LEFT OUTER JOIN + LEFT SEMI JOIN, o que significa que o ClickHouse retorna os valores das colunas de cada linha da tabela à esquerda, combinados com os valores das colunas de uma linha correspondente da tabela à direita ou, se não houver correspondência, com os valores padrão das colunas da tabela à direita.
Se uma linha da tabela à esquerda tiver mais de uma correspondência na tabela à direita, o ClickHouse retornará apenas os valores das colunas combinados da primeira correspondência encontrada (o produto cartesiano fica desabilitado).
Da mesma forma, o RIGHT ANY JOIN é a combinação de RIGHT OUTER JOIN + RIGHT SEMI JOIN.
E o INNER ANY JOIN é um INNER JOIN com o produto cartesiano desabilitado.
O exemplo a seguir demonstra o LEFT ANY JOIN com um exemplo abstrato usando duas tabelas temporárias (left_table e right_table) criadas com a função de tabela values:
RIGHT ANY JOIN:
INNER ANY JOIN:
ASOF JOIN
ASOF JOIN oferece recursos de correspondência não exata.
Se uma linha da tabela à esquerda não tiver uma correspondência exata na tabela à direita, a linha mais próxima da tabela à direita será usada como correspondência.
Isso é particularmente útil para análises de séries temporais e pode reduzir drasticamente a complexidade da consulta.
O exemplo a seguir faz uma análise de séries temporais de dados do mercado de ações.
Uma tabela quotes contém cotações de símbolos de ações com base em horários específicos do dia.
Nos dados de exemplo, o preço é atualizado a cada 10 segundos.
Uma tabela trades lista negociações de símbolos — um determinado volume de um símbolo foi comprado em um horário específico:
Para calcular o custo efetivo de cada negociação, precisamos associar as negociações ao horário de cotação mais próximo.
Isso é simples e enxuto com o ASOF JOIN, em que você usa a cláusula ON para especificar uma condição de correspondência exata e a cláusula AND para especificar a condição de correspondência mais próxima — para um símbolo específico (correspondência exata), você procura a linha com o horário “mais próximo” da tabela quotes exatamente no momento da negociação desse símbolo ou antes dele (correspondência não exata):
A cláusula
ON do ASOF JOIN é obrigatória e especifica uma condição de correspondência exata junto à condição de correspondência não exata da cláusula AND.