Tenho uma mesa com, digamos, cores preferidas. Para cada pessoa, armazenamos a cor favorita e a data efetiva. Se a pessoa mudar de preferência, armazenamos a nova com uma data efetiva mais recente. Exemplo:
name color eff_date
John Green 2014-03-07
Luis Red 2014-03-07
Luis Yellow 2015-05-02
Nina Blue 2015-07-06
Se quisermos pegar a cor preferida atual de Luis:
SELECT color
FROM fav_colors
WHERE name='Luis'
AND eff_date=( SELECT max(eff_date) FROM fav_colors WHERE name='Luis' )
Agora decidimos que as pessoas podem mudar sua cor favorita a qualquer momento, mas a mudança só será efetivada a partir de 1º de janeiro. Portanto, mesmo que Luis tenha inserido um registro que diga que sua cor favorita é Amarelo, a consulta deve retornar o valor antigo (Vermelho) até 1º de janeiro de 2016.
SELECT color
FROM fav_colors
WHERE name='Luis'
AND eff_date=( SELECT max(eff_date) FROM fav_colors WHERE name='Luis' and eff_date < '1 jan 2015' )
Esta consulta parece ok, mas não retornará nenhum registro para Nina. As regras dizem que um recém-chegado pode escolher a cor favorita imediatamente, sem esperar pelo próximo dia 1º de janeiro. Em outras palavras, "se possível, faça um registro de 1º de janeiro ou antes; se não for possível, qualquer registro; leve o mais recente". Isto é o que eu consegui escrever:
SELECT color
FROM fav_colors
WHERE name='Luis'
AND eff_date= ISNULL(
( SELECT max(eff_date) FROM fav_colors WHERE name='Luis' and eff_date < '1 jan 2015' ),
( SELECT max(eff_date) FROM fav_colors WHERE name='Luis' )
)
Existe uma maneira mais elegante ou mais eficiente de obter esse resultado?
Não tenho controle sobre a estrutura das tabelas, elas são da PeopleSoft.
Se Nina fez duas seleções este ano, quero mostrar a mais recente.
Eu explico como fazer isso aqui: http://blogs.lobsterpot.com.au/2014/07/08/ssis-lookup-transformation-in-t-sql/
O conceito básico é usar OUTER APPLY com TOP (1). No seu caso, pode ser necessário começar com a lista de pessoas que você está procurando. Assim:
A postagem detalha como o Query Optimizer só fará a segunda pesquisa se a primeira falhar. É realmente muito eficiente com o índice correto no lugar (em
(name, eff_date) include (color)
).Oh - se a cor puder ser NULL legitimamente, teste uma coluna diferente na subconsulta c2.
Você pode simplificar a primeira e a segunda consulta com
TOP / ORDER BY
:No entanto, não retornará nada para Nina. Você pode usar outra subconsulta e combiná-las com
UNION ALL
mais umaTOP
ou comCOALESCE()
(ouISNULL()
como na sua consulta):Se você quiser fazer esta verificação para mais de uma (ou todas as) pessoas na mesa, você pode usar
OUTER APPLY
, como @RobFarley's explica em sua resposta .)Acho que você precisa alterar o tipo de dados da
eff_date
colunaDATETIME
para evitar problemas com pessoas fazendo duas ou mais seleções no mesmo dia.A
PostYearStart_MAX_eff_date
coluna noCTE
talvez deva ser alteradaMIN
dependendo da sua resposta à minha pergunta nos comentários.Seu problema vem do fato de você estar misturando/usando a mesma coluna para dois tipos de informação:
Para tornar seu modelo de dados mais elegante e dar mais liberdade, considere adicionar a coluna "Data atualizada". Em seguida, você pode preenchê-lo com as informações da coluna "Data efetiva" que está usando agora. Ao mesmo tempo, a coluna "Data Efetiva" presente conterá a Data Efetiva real, por exemplo, 1º de janeiro de 2015.