2009-05-09 17 views
15

Tengo una tabla de la siguiente maneraSQL: Usando Top 1 en consulta UNION con la Orden Por

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 

supone que tengo que encontrar las tasas de todos los que son eficaces para la fecha actual y después de ella. Así que para obtener la tasa efectiva actual, yo uso

SELECT TOP 1 * from table 
where effective_date < '05/05/2009' 
order by effective date desc 

de las tasas después de la fecha actual la consulta es

SELECT * from table 
where effective_date > '05/05/2009' 

combinar estas dos resultado yo uso un sindicato 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 conseguir 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 

que no tienen la menor idea de por qué sucede esto? ¿Alguna sugerencia?

+1

No estoy seguro de que sus resultados "esperados" sean realmente los resultados que debe esperar ... 3/15/2009 es el "penúltimo" registro "más reciente anterior" antes de la fecha de búsqueda de '5/5/2009 '... solo debería obtener 3 registros en su conjunto de resultados esperados. – datacop

Respuesta

24

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' 
+0

¿Esto no aborda el problema de 'top x' dentro de una consulta de la Unión? (Supongo que itr pero no ha jugado con esto en MSSS) – Karl

+0

Sí, esto funciona. Lo probé contra SQL Server 2005. – splattne

+0

Sí, la versión editada de su respuesta funciona (ajustando el orden por consulta en una consulta no ordenada por la unión). Al igual que con los gatos, hay una docena de maneras diferentes de desollarlos. Verifiqué tu consulta para devolver los mismos resultados que los míos. El tuyo es ideal para situaciones rápidas y sucias de "dato de coña ahora" ... Me gusta el método CTE que describí porque una vez que está escrito, puedes hacer lo que quieras con los datos. (es decir, Dame la segunda tasa más alta [pero no la más anterior] y todas las tasas "actuales") – datacop

1

Creo que las consultas anteriores están excluidas el 01/05/2009 usando < y> en lugar de < = y> =.

7

del pedido por parte de una instrucción select que es parte de una unión se ignora. Por lo tanto, su TOP 1 está seleccionando algún registro arbitrario (probablemente el primer registro por la clave agrupada para la tabla).

+0

Exactamente y bien dicho. Me he encontrado con este problema exacto antes. –

2

orden por no es válido cuando se utiliza con una Unión ...

trabajé hasta un polvo rápido y sucio cosita usando expresión de tabla común con un poco de Rango y Caso engaño declaración a obtener los resultados que buscaba ..

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á pasando ...

el CTE define la velocidad, la fecha actual y la clasificación banderas devueltos por la consulta ...

El CASE separa los resultados en aquellos que son anteriores a la fecha de búsqueda, y aquellos que están después de la fecha de búsqueda .. Usamos los resultados del caso (Cur) en nuestra unión para obtener los resultados de la lista de particiones ...

La función Rank() ordena la lista creando una partición con los mismos criterios que utiliza la instrucción CASE para separar la lista ... luego ordenamos por fecha de entrada en forma descendente. Esto se llevará a la lista de "pasado" y hacer que sea más reciente "pasado" rango de entrada 1 ..

Luego, en la parte de unión de la consulta ..

En la parte superior, que estamos recibiendo el rango y fecha de la lista "pasada" (cur = 0) y la primera entrada en la lista "pasada" ... (ordenar = 1) ... que devolverá 1 registro (o 0 si no hay registros anteriores al fecha de búsqueda) ..

Luego unión que con todos los registros de la lista "actual" (act = 1)

.. Entonces, finalmente, que tomar los resultados de la unión .. y para que por la fecha efectiva que nos da todos los registros actuales y el registro anterior "más actual".