postgresql工作时间简化查询
postgresql working hours simplify query
我需要一些查询简化方面的帮助(比如避免重复等)
http://www.sqlfiddle.com/#!17/3607d/1/0
我们有 2 个对象:
working hours
定义:mon_from
, mon_to
, tue_from
...;如果值为 null
那么那天不工作
office
定义为 name
和 timezone
和 working_hours_id
需要简化查找该办公室现在是否工作的查询,如果办公室没有指定工作时间,则它是 24/7 开放的。
SELECT
name,
(CURRENT_TIMESTAMP::time AT TIME ZONE timezone)::time,
(workinghours.id IS NULL) OR ((
((CURRENT_TIMESTAMP::time AT TIME ZONE timezone)::time BETWEEN mon_from AND mon_to
AND EXTRACT(isodow FROM CURRENT_TIMESTAMP AT TIME ZONE timezone) = 1) OR
((CURRENT_TIMESTAMP::time AT TIME ZONE timezone)::time BETWEEN tue_from AND tue_to
AND EXTRACT(isodow FROM CURRENT_TIMESTAMP AT TIME ZONE timezone) = 2) OR
((CURRENT_TIMESTAMP::time AT TIME ZONE timezone)::time BETWEEN wed_from AND wed_to
AND EXTRACT(isodow FROM CURRENT_TIMESTAMP AT TIME ZONE timezone) = 3) OR
((CURRENT_TIMESTAMP::time AT TIME ZONE timezone)::time BETWEEN thu_from AND thu_to
AND EXTRACT(isodow FROM CURRENT_TIMESTAMP AT TIME ZONE timezone) = 4) OR
((CURRENT_TIMESTAMP::time AT TIME ZONE timezone)::time BETWEEN fri_from AND fri_to
AND EXTRACT(isodow FROM CURRENT_TIMESTAMP AT TIME ZONE timezone) = 5) OR
((CURRENT_TIMESTAMP::time AT TIME ZONE timezone)::time BETWEEN sat_from AND sat_to
AND EXTRACT(isodow FROM CURRENT_TIMESTAMP AT TIME ZONE timezone) = 6) OR
((CURRENT_TIMESTAMP::time AT TIME ZONE timezone)::time BETWEEN sun_from AND sun_to
AND EXTRACT(isodow FROM CURRENT_TIMESTAMP AT TIME ZONE timezone) = 7)
) IS True) AS in_workinghours
FROM office
LEFT JOIN workinghours ON (workinghours.id = office.workinghours_id)
SELECT
name,
today_time,
(workinghours.id IS NULL) OR (today_time BETWEEN today_wtime[1] AND today_wtime[2]) AS in_workinghours
FROM office
LEFT JOIN workinghours ON (workinghours.id = office.workinghours_id)
CROSS JOIN LATERAL (
SELECT
(CURRENT_TIMESTAMP::time AT TIME ZONE timezone)::time AS today_time,
CASE EXTRACT(isodow FROM CURRENT_TIMESTAMP AT TIME ZONE timezone)
WHEN 1 THEN ARRAY[mon_from, mon_to]
WHEN 2 THEN ARRAY[tue_from, tue_to]
WHEN 3 THEN ARRAY[wed_from, wed_to]
WHEN 4 THEN ARRAY[thu_from, thu_to]
WHEN 5 THEN ARRAY[fri_from, fri_to]
WHEN 6 THEN ARRAY[sat_from, sat_to]
WHEN 7 THEN ARRAY[sun_from, sun_to]
END AS today_wtime) as wtime
使用子查询而不是横向连接和数组的变体:
SELECT
name,
ts::time time_at_office,
(workinghours_id IS NULL) OR
(CASE EXTRACT(ISODOW FROM ts)
WHEN 1 THEN ts::time BETWEEN mon_from AND mon_to
WHEN 2 THEN ts::time BETWEEN tue_from AND tue_to
WHEN 3 THEN ts::time BETWEEN wed_from AND wed_to
WHEN 4 THEN ts::time BETWEEN thu_from AND thu_to
WHEN 5 THEN ts::time BETWEEN fri_from AND fri_to
WHEN 6 THEN ts::time BETWEEN sat_from AND sat_to
WHEN 7 THEN ts::time BETWEEN sun_from AND sun_to
END) AS in_workinghours
FROM
(SELECT
*,
CURRENT_TIMESTAMP AT TIME ZONE timezone AS ts
FROM office
LEFT JOIN workinghours ON (workinghours.id = office.workinghours_id)) owh
我需要一些查询简化方面的帮助(比如避免重复等)
http://www.sqlfiddle.com/#!17/3607d/1/0
我们有 2 个对象:
working hours
定义:mon_from
,mon_to
,tue_from
...;如果值为null
那么那天不工作office
定义为name
和timezone
和working_hours_id
需要简化查找该办公室现在是否工作的查询,如果办公室没有指定工作时间,则它是 24/7 开放的。
SELECT
name,
(CURRENT_TIMESTAMP::time AT TIME ZONE timezone)::time,
(workinghours.id IS NULL) OR ((
((CURRENT_TIMESTAMP::time AT TIME ZONE timezone)::time BETWEEN mon_from AND mon_to
AND EXTRACT(isodow FROM CURRENT_TIMESTAMP AT TIME ZONE timezone) = 1) OR
((CURRENT_TIMESTAMP::time AT TIME ZONE timezone)::time BETWEEN tue_from AND tue_to
AND EXTRACT(isodow FROM CURRENT_TIMESTAMP AT TIME ZONE timezone) = 2) OR
((CURRENT_TIMESTAMP::time AT TIME ZONE timezone)::time BETWEEN wed_from AND wed_to
AND EXTRACT(isodow FROM CURRENT_TIMESTAMP AT TIME ZONE timezone) = 3) OR
((CURRENT_TIMESTAMP::time AT TIME ZONE timezone)::time BETWEEN thu_from AND thu_to
AND EXTRACT(isodow FROM CURRENT_TIMESTAMP AT TIME ZONE timezone) = 4) OR
((CURRENT_TIMESTAMP::time AT TIME ZONE timezone)::time BETWEEN fri_from AND fri_to
AND EXTRACT(isodow FROM CURRENT_TIMESTAMP AT TIME ZONE timezone) = 5) OR
((CURRENT_TIMESTAMP::time AT TIME ZONE timezone)::time BETWEEN sat_from AND sat_to
AND EXTRACT(isodow FROM CURRENT_TIMESTAMP AT TIME ZONE timezone) = 6) OR
((CURRENT_TIMESTAMP::time AT TIME ZONE timezone)::time BETWEEN sun_from AND sun_to
AND EXTRACT(isodow FROM CURRENT_TIMESTAMP AT TIME ZONE timezone) = 7)
) IS True) AS in_workinghours
FROM office
LEFT JOIN workinghours ON (workinghours.id = office.workinghours_id)
SELECT
name,
today_time,
(workinghours.id IS NULL) OR (today_time BETWEEN today_wtime[1] AND today_wtime[2]) AS in_workinghours
FROM office
LEFT JOIN workinghours ON (workinghours.id = office.workinghours_id)
CROSS JOIN LATERAL (
SELECT
(CURRENT_TIMESTAMP::time AT TIME ZONE timezone)::time AS today_time,
CASE EXTRACT(isodow FROM CURRENT_TIMESTAMP AT TIME ZONE timezone)
WHEN 1 THEN ARRAY[mon_from, mon_to]
WHEN 2 THEN ARRAY[tue_from, tue_to]
WHEN 3 THEN ARRAY[wed_from, wed_to]
WHEN 4 THEN ARRAY[thu_from, thu_to]
WHEN 5 THEN ARRAY[fri_from, fri_to]
WHEN 6 THEN ARRAY[sat_from, sat_to]
WHEN 7 THEN ARRAY[sun_from, sun_to]
END AS today_wtime) as wtime
使用子查询而不是横向连接和数组的变体:
SELECT
name,
ts::time time_at_office,
(workinghours_id IS NULL) OR
(CASE EXTRACT(ISODOW FROM ts)
WHEN 1 THEN ts::time BETWEEN mon_from AND mon_to
WHEN 2 THEN ts::time BETWEEN tue_from AND tue_to
WHEN 3 THEN ts::time BETWEEN wed_from AND wed_to
WHEN 4 THEN ts::time BETWEEN thu_from AND thu_to
WHEN 5 THEN ts::time BETWEEN fri_from AND fri_to
WHEN 6 THEN ts::time BETWEEN sat_from AND sat_to
WHEN 7 THEN ts::time BETWEEN sun_from AND sun_to
END) AS in_workinghours
FROM
(SELECT
*,
CURRENT_TIMESTAMP AT TIME ZONE timezone AS ts
FROM office
LEFT JOIN workinghours ON (workinghours.id = office.workinghours_id)) owh