SQL: Usando Top 1 em consulta UNION com Order By
-
20-08-2019 - |
Pergunta
Eu tenho uma tabela como abaixo
Rate Effective_Date
---- --------------
5.6 02/02/2009
5.8 05/01/2009
5.4 06/01/2009
5.8 12/01/2009
6.0 03/15/2009
eu deveria encontrar as todas as taxas que são eficazes para a data atual e depois dela. Assim, para obter a taxa efetiva atual, eu uso
SELECT TOP 1 * from table
where effective_date < '05/05/2009'
order by effective date desc
para as taxas depois da data atual a consulta é
SELECT * from table
where effective_date > '05/05/2009'
Para combinar esses dois resultado eu uso uma união como
SELECT TOP 1 * from table
where effective_date < '05/05/2009'
order by effective date desc
UNION
SELECT * from table
where effective_date > '05/05/2009'
O resultado esperado é
Rate Effective Date
---- --------------
5.8 05/01/2009
5.4 06/01/2009
5.8 12/01/2009
6.0 03/15/2009
Mas eu recebo o resultado real como
Rate Effective Date
---- --------------
5.6 02/02/2009
5.4 06/01/2009
5.8 12/01/2009
6.0 03/15/2009
Eu não tenho a menor idéia de por que isso acontece? Alguma sugestão?
Solução
Ele funciona da seguinte maneira:
select *
from (
select top 1 *
from table
where effective_date <= '05/05/2009'
order by effective_date desc
) as current_rate
union all
select *
from table
where effective_date > '05/05/2009'
Outras dicas
A Ordem por em uma instrução SELECT que faz parte de uma união é ignorado. Daí o seu TOP 1 está selecionando algum registro arbitrário (provavelmente o primeiro registro pela chave de cluster para a tabela).
Order By é inválido quando usado com uma União ...
Eu trabalhei até uma rapidinha e sujo coisinha usando Common Table Expression com algum Rank e caso declaração truques para obter os resultados que você estava procurando ..
WITH CTE_RATES ( RATE, EFFECTIVE_DATE, CUR, SORT )
AS (
SELECT
Rate,
Effective_date,
CASE WHEN Effective_date > '5/5/2009' THEN 1
ELSE 0
END,
RANK() OVER (PARTITION BY
CASE WHEN EFFECTIVE_DATE > '5/5/2009' THEN 1
ELSE 0
END
ORDER BY EFFECTIVE_DATE DESC)
FROM TestTable
)
SELECT RATE, EFFECTIVE_DATE
FROM (
SELECT RATE, EFFECTIVE_DATE
FROM CTE_RATES
WHERE CUR = 0 AND SORT = 1
UNION ALL
SELECT RATE, EFFECTIVE_DATE
FROM CTE_RATES
WHERE CUR = 1
) AS QRY
ORDER BY EFFECTIVE_DATE
Para explicar o que está acontecendo ...
O CTE define a taxa, data, bandeiras atuais e de classificação retornados da consulta ...
O caso separa os resultados em aqueles que são anteriores à data de pesquisa, e aqueles que são após a data de pesquisa .. Nós usamos os resultados do caso (CUR) em nossa união para puxar os resultados da lista particionado. .
funçãoO Rank (), em seguida, classifica a lista criando uma partição nos mesmos critérios que os usos instrução case para separar a lista .. então nós ordem até a data efetiva em ordem decrescente de moda. Isso levará a lista "passado" e torná-lo é mais atual "passado" rank entrada 1 ..
Em seguida, na parte da união da consulta ..
Na parte superior, estamos recebendo a classificação ea data a partir da lista "passado" (cur = 0) e a primeira entrada na lista de "passado" .. (sort = 1) .. que irá retornar 1 registro (ou 0 se não há registros que são anteriores à data de busca) ..
Então nós união que com todo o registro da lista "atual" (cur = 1)
Então, finalmente .. tomamos os RESULTADOS DA UNIÃO .. e para que até a data efetiva nos dando todos os registros atuais, e o recorde anterior "mais atual".
Eu acredito que as consultas acima estão excluindo 05/01/2009 usando