Как найти соседние записи в таблице SQL с точки зрения месяца и года? - PullRequest
0 голосов
/ 29 мая 2019

Пожалуйста, помогите мне оптимизировать мой SQL-запрос.

У меня есть таблица с полями: date, commodity_id, exp_month_id, exp_year, price, где первые 4 поля являются первичным ключом. Месяцы обозначаются буквами в алфавитном порядке: например, F (для января), G (для февраля), H (для марта) и т. Д. Таким образом, буква более отдаленного от месяца месяца месяца будет больше, чем буква менее удаленного месяца (F

Мне нужно рассчитать разницу между ценами (градиентом) соседних записей в терминах exp_month_id, exp_year. В качестве первого шага я хочу определить для каждой пары (exp_month_id, exp_year) действительную пару (next_month_id, next_year). Основная проблема здесь в том, что если текущий exp_month_id является последним в году, то next_year = exp_year + 1 и next_month_id должны быть первыми в году.

Я написал следующий запрос для выполнения работы:

WITH trading_months AS (
    SELECT DISTINCT commodity_id,
                    exp_month_id
      FROM futures
     ORDER BY exp_month_id
)
SELECT DISTINCT f.commodity_id,
                f.exp_month_id,
                f.exp_year,
                (
                WITH [temp] AS (
                        SELECT exp_month_id
                          FROM trading_months
                         WHERE commodity_id = f.commodity_id
                    )
                    SELECT exp_month_id
                      FROM [temp]
                     WHERE exp_month_id > f.exp_month_id
                    UNION ALL
                    SELECT exp_month_id
                      FROM [temp]
                     LIMIT 1
                )
                AS next_month_id,
                (
                    SELECT CASE WHEN EXISTS (
                                   SELECT commodity_id,
                                          exp_month_id
                                     FROM trading_months
                                    WHERE commodity_id = f.commodity_id AND 
                                          exp_month_id > f.exp_month_id
                                    LIMIT 1
                               )
                           THEN f.exp_year ELSE f.exp_year + 1 END
                )
                AS next_year
  FROM futures AS f

Этот запрос служит базой для динамической таблицы (представления), которая впоследствии используется для расчета градиента. Однако выполнение этого запроса занимает более одной секунды, и, следовательно, весь процесс занимает минуты. Не могли бы вы помочь мне оптимизировать запрос?

Ответы [ 2 ]

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

Примечание: для поддержки оконной функции требуется Sqlite 3.25 или новее:

Отсутствие выборочных данных (предпочтительно в виде операторов CREATE TABLE и INSERT для легкого импорта) и ожидаемых результатов затрудняет тестирование, но если вашей конечной целью является вычисление разницы в ценах между датами истечения срока действия (Создание вашего вопроса немного проблемы XY , может быть что-то вроде:

SELECT date, commodity_id, price, exp_year, exp_month_id
     , price - lag(price, 1) OVER (PARTITION BY commodity_id ORDER BY exp_year, exp_month_id) AS "change from last price"
FROM futures;
0 голосов
/ 31 мая 2019

Благодаря подсказке @Shawn об использовании оконных функций я мог переписать запрос в гораздо более короткой форме:

CREATE VIEW "futures_nextmonths_win" AS
WITH trading_months AS (
    SELECT DISTINCT commodity_id,
                    exp_month_id,
                    exp_year
    FROM futures)
SELECT commodity_id,
       exp_month_id,
       exp_year,
       lead(exp_month_id) OVER w AS next_month_id,
       lead(exp_year) OVER w AS next_year
FROM trading_months
WINDOW w AS (PARTITION BY commodity_id ORDER BY exp_year, exp_month_id);

, что также немного быстрее, чем оригинал.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...