PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

SQL -- Berechnung von Enddaten ab einem bestimmten Startdatum mit willkürlichen Unterbrechungen

Anstatt nur die Länge der Semester oder die Lücken zwischen ihnen zu betrachten, können Sie mit generate_series() , etwa so:

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

(SQLFiddle-Demo )

Diese weist jedem Tag innerhalb eines Semesters eine willkürliche, aber fortlaufende "Tagesnummer" zu, wobei alle Lücken zwischen den Semestern übersprungen werden.

Sie können dies dann als Unterabfrage/CTE JOIN ed zu Ihrer Schülertabelle:Suchen Sie zuerst die "Tagesnummer" ihres Startdatums und fügen Sie dann 7 * n_weeks hinzu um die "Tagesnummer" ihres Enddatums zu finden, und verbinden Sie sich schließlich wieder, um das tatsächliche Datum für diese "Tagesnummer" zu finden.

Dies setzt voraus, dass für Teilwochen keine besondere Handhabung erforderlich ist – d. h. wenn n_weeks 4 beträgt, muss der Studierende für 28 Tage immatrikuliert sein, die in die Dauer eines Semesters fallen. Der Ansatz könnte angepasst werden, um Wochen zu messen (überschreiten Sie 1 week als letztes Argument für generate_series() ), mit dem zusätzlichen Schritt, herauszufinden, in welcher Woche das start_date des Schülers ist fällt in.

Hier ist eine vollständige Abfrage (SQLFiddle-Demo hier ). ):

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