Em uma pergunta anterior Como mesclar conjuntos de dados sem incluir linhas redundantes? Perguntei sobre a filtragem de dados históricos redundantes durante a importação, mas @DavidSpillett respondeu corretamente que não poderia fazer o que estava tentando fazer.
Em vez de filtrar a tabela durante a importação, agora quero criar uma exibição na tabela que retorne apenas os registros em que o preço foi alterado.
Aqui está o cenário original reformulado para atender a esta pergunta:
Temos uma tabela de preços históricos dos itens. A tabela contém linhas onde o mesmo preço é registrado para várias datas. Quero criar uma visão sobre esses dados que mostre apenas as alterações de preço ao longo do tempo, portanto, se um preço mudar de A para BI, quero vê-lo, mas se "mudar" de B para B, não quero vê-lo .
Exemplo: se o preço ontem foi $ 1, e o preço hoje é $ 1, e não houve outras mudanças de preço, então o preço hoje pode ser inferido do preço ontem, então eu só preciso do registro de ontem.
Exemplo ( http://sqlfiddle.com/#!3/c95ff/1 ):
Table data:
Effective Product Kind Price
2013-04-23T00:23:00 1234 1 1.00
2013-04-24T00:24:00 1234 1 1.00 -- redundant, implied by record 1
2013-04-25T00:25:00 1234 1 1.50
2013-04-26T00:26:00 1234 1 2.00
2013-04-27T00:27:00 1234 1 2.00 -- redundant, implied by record 4
2013-04-28T00:28:00 1234 1 1.00 -- not redundant, price changed back to 1.00
Expected view data:
Effective Product Kind Price
2013-04-23T00:23:00 1234 1 1.00
2013-04-25T00:25:00 1234 1 1.50
2013-04-26T00:26:00 1234 1 2.00
2013-04-28T00:28:00 1234 1 1.00
Minha tentativa inicial usou ROW_NUMBER:
SELECT
Effective,
Product,
Kind,
Price
FROM
(
SELECT
History.*,
ROW_NUMBER() OVER
(
PARTITION BY
Product,
Kind,
Price
ORDER BY
Effective ASC
) AS RowNumber
FROM History
) H
WHERE RowNumber = 1
ORDER BY Effective
Que retornou:
Effective Product Kind Price
2013-04-23T00:23:00 1234 1 1.00
-- not 2013-04-24, good
2013-04-25T00:25:00 1234 1 1.50
2013-04-26T00:26:00 1234 1 2.00
-- not 2013-04-27, good
-- not 2013-04-28, bad
Tentei pesquisar por uma pergunta/resposta semelhante, mas é difícil descobrir como formular a pesquisa, um exemplo vale muitas palavras.
Qualquer sugestão é apreciada. Obrigado
SQLfiddle
Este é um bom plano de execução para o pequeno número de linhas fornecido na pergunta. Para uma tabela maior, o índice ideal para esta consulta é:
Esse índice é essencialmente as chaves de índice agrupadas em uma ordem mais útil. Dependendo de como a tabela é usada para outras consultas, pode ser melhor substituir o índice clusterizado em vez de criar esse novo índice.
Não use porcentagens de custo estimado em lote para comparar consultas diferentes. Esta não é uma comparação válida em geral. Os custos são sempre estimativas do otimizador e não devem ser usados dessa forma. Verifique as métricas de desempenho reais (tempo decorrido, E/S, uso de CPU, uso de memória) de todas as maneiras, mas não confie nas porcentagens.
Se esta consulta ou aquela baseada
ROW_NUMBER
é mais eficiente depende da distribuição dos dados e de outros fatores. Cada um tem suas vantagens e desvantagens. Essa consulta tem vantagens quando há muitas linhas para cada combinação (produto, tipo).Teste no SQL-Fiddle
Obrigado a @JonSeigel por me direcionar para Query (duração) diferente entre alteração de valor de dados . Estou postando uma versão modificada de sua resposta aqui porque meu problema era um pouco diferente (necessário
PARTITION BY
noROW_NUMBER
), então talvez alguém ache a variante útil. Se você achar esta resposta útil, vote na resposta de Jon, porque eu não teria chegado a isso sem ela.Em meus testes de tempo bastante básicos em uma tabela contendo ~ 3 milhões de registros, esta solução é cerca de 3 vezes mais rápida que a resposta de @AK_ .
Esta é a consulta:
Para um número maior de linhas:
As classificações podem ser eliminadas usando o índice:
O que é necessário é uma solução LEAD/LAG implementada em 2008. Infelizmente, ela não foi disponibilizada até 2012. Encontrei algumas implementações realmente boas no SQLAuthority . Uma comparação pode ser feita entre o LEAD e o valor atual e a linha retornada onde eles são diferentes.
Para Sql Server 2012 usando Lag ()