Estou trabalhando na criação de um Datawarehouse. Criei uma Dimensão de Tempo (Dim_Time), em intervalos de 5 minutos. As agregações de hora terão [Minutes] = NULL. Para efeito deste exemplo:
CREATE TABLE [dbo].[Dim_Time](
[TimeID] [int] IDENTITY(1,1) NOT NULL,
[StartDateTime] [datetime] NULL,
[Hour] [int] NULL,
[Minute] [int] NULL,
CONSTRAINT [PK_Dim_Time] PRIMARY KEY CLUSTERED
([TimeID] ASC)
) ON [PRIMARY]
GO
Então eu tenho uma tabela de entrada, que é atualizada a cada 5 minutos do banco de dados OLTP.
CREATE TABLE [dbo].[Stg_IncomingQueue](
[IncomingID] [int] IDENTITY(1,1) NOT NULL,
[CustomerID] [int] NOT NULL,
[TimeID] [int] NULL,
[InsertTime] [datetime] NULL,
CONSTRAINT [PK_IncomingQueueMonitor] PRIMARY KEY CLUSTERED
([IncomingID] ASC)
) ON [PRIMARY]
GO
Eu então tenho o seguinte loop While. Seu objetivo é obter o intervalo de tempo de 5 minutos correto (TimeID) relacionado a uma linha de entrada específica:
WHILE 0 < (SELECT COUNT(*) FROM [dba_local].[dbo].[Stg_IncomingQueue] WHERE TimeID IS NULL)
BEGIN
SELECT TOP 1 @IncomingID = IncomingID, @RowInserTime = InsertTime
FROM [dba_local].[dbo].[Stg_IncomingQueue] WHERE TimeID IS NULL
;WITH DimTime
AS (
SELECT MAX(TimeID) AS MaxTimeID FROM [dba_local].[dbo].[Dim_Time]
WHERE StartDateTime < @RowInserTime AND [Minute] IS NOT NULL
)
UPDATE [dba_local].[dbo].[Stg_IncomingQueue]
SET TimeID = (SELECT MaxTimeID FROM DimTime)
WHERE IncomingID = @IncomingID
END
É um processo tão simples e, no entanto, não consigo descobrir uma maneira mais simples de atualizar o TimeID. De acordo com o CTE SELECT no loop, preciso obter o MAX(TimeID) onde o StartDateTime é menor que as linhas InsertTime. Como o tempo é a única relação, estou lutando com todas as opções para fazer isso em 1 consulta sem o loop, mas sinto que é possível
Por favor, alguém pode me ajudar aqui com uma opção melhor ou confirmando que esta é a maneira mais simples.
Muito obrigado pelo seu tempo e ajuda. Wade
Criei o seguinte exemplo minimamente completo e verificável , com base nas duas tabelas da sua pergunta original. Ele usa a instrução LEAD T-SQL para obter um intervalo de tempo da tabela dbo.Dim_Time, que pode ser comparado com as linhas de entrada com bastante facilidade.
Esta peça substitui todo o seu
WHILE
loop, por uma únicaUPDATE
instrução, que é mais eficiente e mais fácil de entender.Os resultados, comparados lado a lado com a tabela Dim_Time:
A saída se parece com:
Supondo que não haja uma grande quantidade de linhas de entrada, isso pode funcionar muito bem. Esteja ciente, estou usando
CONVERT()
para converter adatetime
coluna de entrada em umtime(0)
valor, o que tem um custo do otimizador de consulta não poder usar as estatísticas disponíveis para ajudar a criar um ótimo plano. O plano de consulta "real" para a instrução de inserção mostra este aviso:Se você precisar evitar a conversão de tipo durante a atualização, poderá mover essa carga de trabalho para a operação de inserção atualizando a definição de
dbo.Stg_IncomingQueue
para incluir uma coluna computada persistente, como em:A instrução de atualização então se torna: