Estou com uma dúvida sobre a junção de duas tabelas.
Esquema
CREATE TABLE [dbo].[DCString] (
[ID] [bigint] IDENTITY(1,1) NOT NULL,
[DCDistributionBoxID] [bigint] NOT NULL,
[CurrentMPP] [decimal](18, 2) NULL,
CONSTRAINT [PrimaryKey3] PRIMARY KEY CLUSTERED ( [ID] ASC )
)
ALTER TABLE [dbo].[DCString]
ADD CONSTRAINT [FK_DCString_DCDistributionBox] FOREIGN KEY([DCDistributionBoxID])
REFERENCES [dbo].[DCDistributionBox] ([ID])
CREATE TABLE [dbo].[StringData](
[DCStringID] [bigint] NOT NULL,
[TimeStamp] [datetime] NOT NULL,
[DCCurrent] [decimal](18, 2) NULL,
CONSTRAINT [PrimaryKey4] PRIMARY KEY CLUSTERED ( [TimeStamp] DESC, [DCStringID] ASC)
)
A [StringData]
tabela tem as seguintes estatísticas de armazenamento:
- Espaço para dados: 26.901,86 MB
- Contagem de linhas: 131.827.749
- Particionado: verdadeiro
- Contagem de partições: 62
Agora quero juntar os dados da [StringData]
tabela com os dados da [DCString]
tabela.
Algo como:
declare @begin datetime = '22.02.2016';
declare @end datetime = '23.02.2016';
declare @dcStringID bigint = 6658;
SELECT [DCString].[ID], [StringData].[TimeStamp]
FROM [StringData]
RIGHT OUTER JOIN [StringData] ON [StringData].[DCStringID] = [DCString].[ID]
WHERE [StringData].[ID] = @dcStringID
AND [StringData].[TimeStamp] >= @begin
AND [StringData].[TimeStamp] < @end;
O que eu espero no intervalo de datas pesquisado onde [StringData]
existem dados correspondentes na tabela é o seguinte:
ID | TimeStamp
6658 | 22.02.2016 10:00:00
6658 | 22.02.2016 11:00:00
6658 | 22.02.2016 12:00:00
... e em um intervalo de datas pesquisado em que não [StringData]
existem dados correspondentes na tabela é este:
ID | TimeStamp
6658 | NULL
Pergunta
O que recebo em um intervalo de datas pesquisado em que não [StringData]
existem dados correspondentes na tabela é um resultado de 0 linhas. Por quê?
Eu simplesmente quero sempre obter todos os [DCString].[ID]
s. O que há de errado com meu JOIN ou eu errei completamente?
Atualização 1 (relacionada à resposta de @Aaron Bertrand):
Já tentei do seu jeito, mas tenho que cancelar o teste da consulta porque depois de 10min ainda está rodando. Ficou assim:
declare @begin datetime = '22.02.2016';
declare @end datetime = '23.02.2016';
declare @dcStringID bigint = 6658;
SELECT [DCString].[ID], [StringData].[TimeStamp]
FROM [StringData]
LEFT JOIN [DCString]
ON [StringData].[DCStringID] = [DCString].[ID]
AND [StringData].[TimeStamp] >= @begin
AND [StringData].[TimeStamp] < @end
WHERE [StringData].[ID] = @dcStringID;
Se entendi seus requisitos corretamente, você deseja cada linha em
DCString
, mesmo quando não houver linha correspondente emStringData
. As duas consultas que você tem agora estão incorretas:DCString RIGHT JOIN StringData
- isso é inverso ao que você parece querer (e é uma das razões pelas quais as pessoas sãs evitamRIGHT JOIN
sempre que possível).StringData LEFT JOIN DCString
- isso também é inverso ao que você parece querer. Sugeri mudar oRIGHT JOIN
para aLEFT JOIN
, sem alterar a ordem da tabela, mas você trocou as tabelas também, sem alteração líquida. Por que aquele não está voltando no momento pode ser devido a muitas coisas, não temos como especular. Tente gerar um plano estimado e veja se você está sendo vítima de algum desses motivos .Novamente, com base no que eu acho que você deseja (você obterá respostas melhores se fornecer alguns dados de amostra e os resultados desejados):
Leitura adicional:
A resposta de Aaron Bertrand está correta e seu conselho é bom. Sua interpretação de "atualização 1" não é a mesma que a consulta dele. Aposto que se você copiar o código literalmente, funcionará.
Pode ajudar pensar em "externo" e "interno" como conjuntos em um diagrama de Venn com um círculo aninhado dentro do outro: a mesa externa é o conjunto que contém a mesa interna. Portanto, quando dizemos
R left outer join S
, queremos dizer que a mesa à esquerda,R
, é a de fora.Algumas pessoas chamam a tabela externa de tabela preservada para reforçar a ideia de que todas as suas linhas são preservadas no JOIN. Também ouvi as colunas da tabela externa serem chamadas de coluna vertebral que "pendura" os dados da tabela interna.
A razão para preferir a ESQUERDA à DIREITA é psicológica. A maioria das pessoas parece organizar o SELECT para colocar as colunas da tabela externa primeiro (à esquerda) e mencionar a tabela externa primeiro na cláusula FROM. Portanto, todas as "coisas importantes" estão à esquerda e as "poderosas" estão à direita. Eu sei por mim mesmo que sempre que alguém me traz uma junção DIREITA que não está funcionando como esperado, a primeira coisa que faço é reformulá-la como uma junção ESQUERDA, e isso geralmente é suficiente para ver o que está errado.