有一个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等的记录。如果星期几较低,则显示下周的日期。
有人会有任何关于优化这个的建议吗?
加6,减去the day of the week dow
并取模7(%
is the modulo operator)。
这是要添加的天数(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";
在不查看数据和索引的情况下很难知道,但是您可以尝试计算DOW一次并使用它而不是提取这么多次,这将使您的查询更有效,更可读。
EG
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)
一个改进是仅计算当前的一周中的一天:
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";