Istället för att bara titta på terminslängden eller klyftorna mellan dem kan du skapa en lista över alla datum som ligger inom en termin med generate_series()
, så här:
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
Detta tilldelar varje dag som är under en termin ett godtyckligt men sekventiellt "dagnummer", vilket hoppar över alla luckor mellan terminerna.
Du kan sedan använda detta som en underfråga/CTE JOIN
ed till din elevtabell:hitta först "dagnummer" för deras startdatum, lägg sedan till 7 * n_weeks
för att hitta "dagnumret" för deras slutdatum, och slutligen gå tillbaka för att hitta det faktiska datumet för det "dagnumret".
Detta förutsätter att det inte behövs någon speciell hantering för partiella veckor - d.v.s. om n_weeks
är 4, måste studenten vara inskriven i 28 dagar som ligger inom en terminsperiod. Metoden skulle kunna anpassas för att mäta veckor (pass 1 week
som det sista argumentet till generate_series()
), med det ytterligare steget att hitta vilken vecka studentens start_date
faller i.
Här är en fullständig fråga (SQLFiddle-demo här ):
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