PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

SQL - calcul des dates de fin à partir d'une date de début donnée avec des pauses arbitraires

Plutôt que de simplement regarder la durée des semestres ou les écarts entre eux, vous pouvez générer une liste de toutes les dates d'un semestre en utilisant generate_series() , comme ceci :

SELECT
  row_number() OVER () as day_number,
  day
FROM
(
  SELECT
    generate_series(start_date, end_date, '1 day') as day
  FROM
    semesters
) as day_series
ORDER BY 
  day

(Démo SQLFiddle )

Cela attribue à chaque jour d'un semestre un "numéro de jour" arbitraire mais séquentiel, en sautant tous les écarts entre les semestres.

Vous pouvez ensuite l'utiliser comme sous-requête/CTE JOIN à votre table d'étudiants :trouvez d'abord le "numéro de jour" de leur date de début, puis ajoutez 7 * n_weeks pour trouver le "numéro de jour" de leur date de fin, et enfin revenez pour trouver la date réelle de ce "numéro de jour".

Cela suppose qu'il n'y a pas de traitement spécial nécessaire pour les semaines partielles - c'est-à-dire si n_weeks est de 4, l'étudiant doit être inscrit pendant 28 jours qui sont dans la durée d'un semestre. L'approche pourrait être adaptée pour mesurer les semaines (passer 1 week comme dernier argument de generate_series() ), avec l'étape supplémentaire de trouver quelle semaine la start_date de l'étudiant tombe dans.

Voici une requête complète (Démo SQLFiddle ici ):

WITH semester_days AS
(
  SELECT
    semester_id,
    row_number() OVER () as day_number,
    day_date::date
  FROM
  (
    SELECT
      id as semester_id,
      generate_series(start_date, end_date, '1 day') as day_date
    FROM
      semesters
  ) as day_series
  ORDER BY 
    day_date
)
SELECT
  S.id as student_id,
  S.start_date,
  SD_start.semester_id as start_semester_id,
  S.n_weeks,
  SD_end.day_date as end_date,
  SD_end.semester_id as end_semester_id
FROM
  students as S
JOIN
  semester_days as SD_start
  On SD_start.day_date = S.start_date
JOIN
  semester_days as SD_end
  On SD_end.day_number = SD_start.day_number + (7 * S.n_weeks)
ORDER BY
  S.start_date