Расчет форвардных дат в PostgreSQL - PullRequest
0 голосов
/ 28 февраля 2019

Получен запрос PostgreSQL, который работает хорошо, но не кажется очень эффективным ...

SELECT
    _id,
    location,
    day,
    title,
    teacher,
    canceled,
    CASE
      WHEN day <= EXTRACT(dow from CURRENT_DATE)::integer THEN CURRENT_DATE + day + (6 - EXTRACT(dow from CURRENT_DATE)::integer) + "startTime"  
      WHEN day > EXTRACT(dow from CURRENT_DATE)::integer THEN CURRENT_DATE + (day - EXTRACT(dow from CURRENT_DATE)::integer - 1) + "startTime"
    END AS "startTime",
    CASE
      WHEN day <= EXTRACT(dow from CURRENT_DATE)::integer THEN CURRENT_DATE + day + (6 - EXTRACT(dow from CURRENT_DATE)::integer) + "endTime"  
      WHEN day > EXTRACT(dow from CURRENT_DATE)::integer THEN CURRENT_DATE + (day - EXTRACT(dow from CURRENT_DATE)::integer - 1) + "endTime"
    END AS "endTime"
    FROM "Schedules"
    ORDER BY location, day, "startTime";

В этом случае столбец дня - это день недели (1-7, а не 0-6).).Он отображает даты начиная с текущей даты, поэтому, если это среда (день 4), он показывает записи с днем ​​= 4 в качестве текущей даты, днем ​​= 5 - это текущая дата + 1 и т. Д. Если день недели меньше, он показываетдаты следующей недели.

У кого-нибудь есть какие-либо предложения относительно оптимизации этого?

Ответы [ 3 ]

0 голосов
/ 28 февраля 2019

Одним из улучшений является вычисление текущего дня недели только один раз:

SELECT
    _id,
    location,
    day,
    title,
    teacher,
    canceled,
    CASE
        WHEN day <= current.dow THEN CURRENT_DATE + day + (6 - current.dow) + "startTime"
        WHEN day > current.dow THEN CURRENT_DATE + (day - current.dow - 1) + "startTime"
    END AS "startTime",
    CASE
        WHEN day <= current.dow THEN CURRENT_DATE + day + (6 - current.dow) + "endTime"
        WHEN day > current.dow THEN CURRENT_DATE + (day - current.dow - 1) + "endTime"
    END AS "endTime"
    FROM "Schedules"
        FULL JOIN (
            SELECT EXTRACT(dow from CURRENT_DATE)::integer AS dow
        ) AS current
        ON TRUE
    ORDER BY location, day, "startTime";
0 голосов
/ 28 февраля 2019

Добавьте 6, вычтите день недели dow и возьмите его по модулю 7 (% - оператор по модулю ).
Это количество дней (0-6), которое нужно добавить:

SELECT _id, location, day, title, teacher, canceled
      , now()::date + ((day + 6 - EXTRACT(dow from now())::int) % 7) + "startTime"
      , now()::date + ((day + 6 - EXTRACT(dow from now())::int) % 7) + "endTime"
FROM    "Schedules"
ORDER   BY location, day, "startTime";

Связанный:

Или, чтобы избежать повторения выражения (но я сомневаюсь, что это будет быстрее):

SELECT _id, location, day, title, teacher, canceled
     , t.d + "startTime"
     , t.d + "endTime"
FROM   "Schedules" s
, LATERAL (SELECT now()::date + (s.day + 6 - EXTRACT(dow from now())::int) % 7) t(d)
ORDER  BY location, day, "startTime";
0 голосов
/ 28 февраля 2019

Трудно понять, не глядя на ваши данные и индексы, но вы можете попытаться рассчитать DOW один раз и использовать его вместо извлечения столько раз, что сделает ваш запрос более эффективным и более читабельным.

например

SELECT your_columns
      ,case when day <= v.curr_dow then 
                 current_day + day + 6 - v.curr_dow + startTime
            else current_day + day - 1 - v.curr_dow + startTime
            end as startTime
      ...
FROM   your_table
      cross join (values(extract(dow from current_date)::integer)) AS v(curr_dow)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...