Как повторить значения в случае нулевых значений при левом соединении - PullRequest
0 голосов
/ 29 мая 2020

У меня есть таблица с календарем и таблица со ставками. В таблице со ставками нет значений для дней в выходные. Я пытаюсь присоединиться к этим двум, чтобы иметь таблицу, в которой есть ставки на все дни, и мне нужно, чтобы ставки на выходных были последними доступными ставками. Вместо этого он показывает значения NULL, как если бы вы выполняли левое соединение, а запись не существует, она должна просто принимать последнее доступное значение, повторяя предыдущее значение.

У меня есть приведенный ниже код, который работает, но для обработки 7 397 строк требуется 2 минуты, что слишком долго.

Кто-нибудь знает более быстрый способ получить такие же результаты?

SELECT
c.CalendarID, 
MAX(r.RateID)

FROM Dim_Calendar c

LEFT JOIN Dim_Rates r ON r.RateDate <= c.CalendarID

То, что я получаю без <= и просто =, выглядит следующим образом </p>

CalendarID | RateID
20131001   | 2
20131002   | 3
20131003   | 4
20131004   | 5
20131005   | NULL
20131006   | NULL
20131007   | 6

И это желаемая таблица:

CalendarID | RateID
20131001   | 2
20131002   | 3
20131003   | 4
20131004   | 5
20131005   | 5
20131006   | 5
20131007   | 6

Ответы [ 3 ]

1 голос
/ 29 мая 2020

Вы можете использовать LAG() оконную функцию:

SELECT c.CalendarID,
  COALESCE(
    r.RateID,
    LAG(r.RateID, 1) OVER (ORDER BY c.CalendarID),
    LAG(r.RateID, 2) OVER (ORDER BY c.CalendarID)
  ) RateID
FROM Dim_Calendar c LEFT JOIN Dim_Rates r 
ON r.RateDate = c.CalendarID
ORDER BY c.CalendarID

См. демонстрацию . Результатов:

> CalendarID | RateID
> ---------: | :-----
>   20131001 | 2     
>   20131002 | 3     
>   20131003 | 4     
>   20131004 | 5     
>   20131005 | 5     
>   20131006 | 5     
>   20131007 | 6  
1 голос
/ 29 мая 2020

Вы можете использовать коррелированный подзапрос, чтобы заполнить пробелы:

SELECT
    c.CalendarID, 
    (SELECT TOP 1 r.RateID FROM Dim_Rates r
     WHERE r.RateDate <= c.CalendarID AND r.RateID IS NOT NULL
     ORDER BY r.RateDate DESC) AS RateID
FROM Dim_Calendar c
ORDER BY c.CalendarID;

Этот запрос можно улучшить, используя следующий индекс:

CREATE INDEX idx ON Dim_Rates (RateDate, RateID);
0 голосов
/ 29 мая 2020

Как уже указывалось, вам необходимо проверить правильность и охват индексации. Похоже, вы работаете с DW DB, и если это так, вы можете заменить CTE индексированными временными таблицами, если приближение расчетного количества строк в плане запроса не соответствует.

;WITH NormalizedData AS
(
    SELECT
        RateID,CalendarID,
        VirtualGroupID = SUM(LastRecordBeforeGap) OVER (ORDER BY CalendarID ROWS UNBOUNDED PRECEDING)
    FROM
    (
        SELECT RateID,CalendarID,
        LastRecordBeforeGap = CASE WHEN LEAD(RateID) OVER(ORDER BY CalendarID) IS NULL AND RateID IS NOT NULL THEN 1 ELSE 0 END
        FROM
            Dim_Calendar  c
            LEFT JOIN Dim_Rates  r ON r.RateDate = c.CalendarID
    )AS x
)

SELECT 
    RateID = ISNULL(RateID, SUM(RateID) OVER(PARTITION BY VirtualGroupID)),
    CalendarID 
FROM 
    NormalizedData
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...