2017-08-27 4 views
1

je besoin d'une aide avec une simplification de la requête (comme pour éviter etc répétition)postgresql heures de travail simplifient la requête

http://www.sqlfiddle.com/#!17/3607d/1/0

Nous avons 2 objets:

  • working hours définis: mon_from, mon_to, tue_from ...; si la valeur est null alors ne fonctionne pas ce jour-là

  • office défini avec ses name et timezone et working_hours_id

Nécessité de simplifier une requête qui trouve si ce bureau travaille actuellement, si le bureau ne pas travailler heures indiquées, alors il est ouvert 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) 
+1

'(CURRENT_TIMESTAMP :: heure à fuseau horaire TIME ZONE) :: time' peut être simplifiée' (CURRENT_TIMESTAMP AU fuseau horaire TIME ZONE) :: time'. – markusk

Répondre

3
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 
2

Variation qui utilise un sous-requête au lieu de latéral jointures et tableaux:

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