Zamiast patrzeć tylko na długości semestrów lub przerwy między nimi, możesz wygenerować listę wszystkich dat, które mieszczą się w semestrze, używając generate_series()
, tak:
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
To przypisuje każdemu dniu, który jest w trakcie semestru, arbitralny, ale sekwencyjny „numer dnia”, pomijając wszystkie przerwy między semestrami.
Następnie możesz użyć tego jako podzapytania/CTE JOIN
ed do tabeli uczniów:najpierw znajdź „numer dnia” ich daty rozpoczęcia, a następnie dodaj 7 * n_weeks
aby znaleźć „numer dnia” ich daty końcowej, a na koniec dołączyć z powrotem, aby znaleźć rzeczywistą datę dla tego „numeru dnia”.
Zakłada się, że nie jest wymagana żadna specjalna obsługa przez częściowe tygodnie - np. jeśli n_weeks
4 lata, student musi być przyjęty na 28 dni, które mieszczą się w czasie trwania semestru. Podejście można dostosować do mierzenia tygodni (zalicz 1 week
jako ostatni argument generate_series()
), z dodatkowym krokiem znajdowania start_date
tygodnia ucznia wpada.
Oto pełne zapytanie (demo SQLFiddle ):
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