sql >> Base de Datos >  >> RDS >> PostgreSQL

SQL:cálculo de fechas de finalización a partir de una fecha de inicio dada con interrupciones arbitrarias

En lugar de solo mirar la duración de los semestres o las brechas entre ellos, puede generar una lista de todas las fechas que están dentro de un semestre usando generate_series() , así:

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

(Demostración de SQLFiddle )

Esto asigna a cada día que es durante un semestre un "número de día" arbitrario pero secuencial, omitiendo todos los espacios entre semestres.

Luego puede usar esto como una subconsulta/CTE JOIN ed a su tabla de estudiantes:primero busque el "número de día" de su fecha de inicio, luego agregue 7 * n_weeks para encontrar el "número de día" de su fecha de finalización y, finalmente, volver a unirse para encontrar la fecha real de ese "número de día".

Esto supone que no se necesita un manejo especial para las semanas parciales, es decir, si n_weeks es 4, el estudiante debe estar matriculado por 28 días que están dentro de la duración de un semestre. El enfoque podría adaptarse para medir semanas (pasar 1 week como último argumento para generate_series() ), con el paso adicional de encontrar en qué semana start_date del estudiante cae en.

Aquí hay una consulta completa (demostración de SQLFiddle aquí ):

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