Подтвердить что ты не робот

SQL: использование Top 1 в запросе UNION с помощью Order By

У меня есть таблица ниже

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

Я должен найти все ставки, действующие для текущей даты и после нее. Чтобы получить текущую эффективную ставку, я использую

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

для ставок после текущей даты запрос

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

Чтобы объединить эти два результата, я использую объединение как

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'

Ожидаемый результат

Rate Effective Date
---- --------------
5.8  05/01/2009
5.4  06/01/2009
5.8  12/01/2009
6.0  03/15/2009

Но я получаю фактический результат как

Rate Effective Date
---- --------------
5.6  02/02/2009
5.4  06/01/2009
5.8  12/01/2009
6.0  03/15/2009

У меня нет подсказки, почему это происходит? Любые предложения?

4b9b3361

Ответ 1

Он работает следующим образом:

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'

Ответ 2

Заказ By в выражении select, который является частью объединения, игнорируется. Следовательно, ваш TOP 1 выбирает какую-то суровую запись (вероятно, первая запись кластеризованным ключом для таблицы).

Ответ 3

Order By недействителен при использовании с Union...

Я обработал быстрый и грязный материал, используя Common Table Expression, с некоторыми трюками из ранга и дела, чтобы получить результаты, которые вы искали.

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

Чтобы объяснить, что происходит...

CTE определяет флаги скорости, даты, текущего и сортировки, возвращаемые из запроса...

CASE разделяет результаты на те, которые были до даты поиска, и те, которые находятся после даты поиска. Мы используем результаты из случая (Cur) в нашем объединении, чтобы вывести результаты из списка секционированных..

Затем функция Rank() сортирует список, создавая раздел по тем же критериям, что и оператор CASE, чтобы отделить список. Затем мы заказываем по дате вступления в силу по убыванию. Это займет "прошлый" список и сделает его самым текущим "прошлым" рангом записи 1..

Затем в объединенной части запроса..

В верхней части мы получаем ранги и даты из "прошлого" списка (cur = 0) и первой записи в "прошлом" списке.. (sort = 1).., который вернет 1 запись (или 0, если нет записей, которые были до даты поиска).

Затем мы объединяем это со всей записью из "текущего" списка (cur = 1)

Тогда, наконец, возьмем РЕЗУЛЬТАТЫ UNION.. и закажем, чтобы по дате вступления давали нам все текущие записи и "самую последнюю" предыдущую запись.

Ответ 4

Я считаю, что вышеупомянутые запросы исключают 05/01/2009, используя < и > вместо <= и > =.