SQL: Uso de Top 1 en consulta UNION con Ordenar por
-
20-08-2019 - |
Pregunta
Tengo una tabla como la siguiente
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
Se supone que debo encontrar todas las tarifas que son efectivas para la fecha actual y posteriores. Entonces, para obtener la tasa efectiva actual, uso
SELECT TOP 1 * from table
where effective_date < '05/05/2009'
order by effective date desc
para las tarifas después de la fecha actual de la consulta
SELECT * from table
where effective_date > '05/05/2009'
Para combinar estos dos resultados, uso una unión 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'
El resultado esperado es
Rate Effective Date
---- --------------
5.8 05/01/2009
5.4 06/01/2009
5.8 12/01/2009
6.0 03/15/2009
Pero obtengo el 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
No tengo ni idea de por qué sucede esto. ¿Alguna sugerencia?
Solución
Funciona de esta manera:
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'
Otros consejos
Se ignora Order By en una instrucción select que forma parte de una unión. Por lo tanto, su TOP 1 está seleccionando algún registro arbitrario (probablemente el primer registro de la clave agrupada para la tabla).
Ordenar por no es válido cuando se usa con una Unión ...
Trabajé de manera rápida y sucia usando la expresión de tabla común con algunos trucos de declaración de rango y caso para obtener los resultados que estabas buscando ...
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 lo que está sucediendo ...
El CTE define la velocidad, la fecha, los indicadores actuales y de clasificación devueltos por la consulta ...
El CASO separa los resultados en aquellos que son anteriores a la fecha de búsqueda y aquellos que son posteriores a la fecha de búsqueda. Utilizamos los resultados del caso (Cur) en nuestra unión para extraer los resultados de la lista particionada. .
La función Rank () luego ordena la lista creando una partición en el mismo criterio que la declaración CASE usa para separar la lista ... luego ordenamos por fecha efectiva de manera descendente. Esto tomará el & Quot; pasado & Quot; enumerar y hacer que sea más actual " pasado " rango de entrada 1 ..
Luego, en la parte de unión de la consulta ...
En la parte superior, obtenemos el rango y la fecha de " past " list (cur = 0) y la primera entrada en " past " list .. (sort = 1) .. que devolverá 1 registro (o 0 si no hay registros anteriores a la fecha de búsqueda) ..
Luego lo unimos con todo el registro de " current " lista (cur = 1)
Luego, finalmente ... tomamos los RESULTADOS de UNION ... y lo ordenamos para la fecha de vigencia, dándonos todos los registros actuales, y el " más actual " registro anterior.
Creo que las consultas anteriores excluyen 01/05/2009 al usar < y > en lugar de < = y > =.