PostgreSQL
 sql >> Base de Dados >  >> RDS >> PostgreSQL

SQL -- computando datas de término de uma determinada data de início com quebras arbitrárias


Em vez de apenas observar a duração dos semestres ou as lacunas entre eles, você pode gerar uma lista de todas as datas dentro de um semestre usando generate_series() , assim:
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

(demonstração do SQLFiddle )

Isso atribui a cada dia do semestre um "número do dia" arbitrário, mas sequencial, pulando todas as lacunas entre os semestres.

Você pode usar isso como uma subconsulta/CTE JOIN ed para sua tabela de alunos:primeiro encontre o "número do dia" de sua data de início e, em seguida, adicione 7 * n_weeks para encontrar o "número do dia" de sua data de término e, finalmente, junte-se novamente para encontrar a data real desse "número do dia".

Isso pressupõe que não há necessidade de tratamento especial para semanas parciais - ou seja, se n_weeks é 4, o aluno deve estar matriculado por 28 dias que estão dentro da duração de um semestre. A abordagem pode ser adaptada para medir semanas (passar 1 week como último argumento para generate_series() ), com a etapa adicional de descobrir em qual semana a start_date do aluno cai em.

Aqui está uma consulta completa (demo SQLFiddle aqui ):
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