SQL:Использование Top 1 в запросе ОБЪЕДИНЕНИЯ с Order By

StackOverflow https://stackoverflow.com/questions/842798

  •  20-08-2019
  •  | 
  •  

Вопрос

У меня есть таблица, как показано ниже

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

Я понятия не имею, почему это происходит?Есть какие-нибудь предложения?

Это было полезно?

Решение

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

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'

Другие советы

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

Порядок По недействителен при использовании с Объединением...

Я разработал быструю и грязную штуковину, используя 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 определяет скорость, дату, текущие флаги и флаг сортировки, возвращаемые из запроса...

РЕГИСТР разделяет результаты на те, которые предшествуют дате поиска, и те, которые после даты поиска..Мы используем результаты из обращения (Cur) в нашем объединении, чтобы извлечь результаты из секционированного списка..

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

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

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

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

И вот, наконец..мы берем РЕЗУЛЬТАТЫ ОБЪЕДИНЕНИЯ..и закажите это по дате вступления в силу, предоставив нам все текущие записи и "самую последнюю" предыдущую запись.

Я полагаю, что приведенные выше запросы исключают 01.05.2009, используя < и > вместо <= и >=.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top