Aufeinanderfolgende Kalendertage erkennen
Datumsarithmetik und Zeilennummern verwenden, um durchgehende Tagesfolgen zu finden
Aufeinanderfolgende Kalendertage erkennen ist eine kostenlose Coding Interview Prep-Lektion auf CoddyKit. Dies ist Lektion 1 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Coding Interview Prep-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Coding Interview Prep-Kurs umfasst insgesamt 4 Lektionen.
Die Aufgabenstellung im Interview
Interviewer lieben Fragen zu Aktivitätsserien, weil sie zeigen, ob Sie Fensterfunktionen und Datumsarithmetik wirklich verstehen. Eine typische Aufgabenstellung lautet: „Gegeben sei eine Tabelle mit Login-Daten von Benutzern. Finden Sie jede ununterbrochene Folge aufeinanderfolgender Kalendertage.“
Der naive Ansatz besteht darin, jede Zeile per Self-Join mit der nächsten zu vergleichen. Das skaliert bei großen Tabellen schlecht und ist umständlich zu formulieren. Die professionelle Lösung verwendet die Lücken-und-Inseln-Technik. In dieser Lektion lernen Sie, aufeinanderfolgende Tage mithilfe von Zeilennummern und Datumsarithmetik sauber zu erkennen.
Die Beispieldaten
In dieser Lektion verwenden wir eine Tabelle logins mit einer Zeile pro Benutzer und Tag, an dem er aktiv war. Es wird vorausgesetzt, dass Duplikate bereits entfernt wurden (ein Login pro Kalendertag).
user_id— wer sich angemeldet hatlogin_date— ein DATE-Wert
Für Benutzer 1 lauten die Daten 1., 2. und 3. Januar, dann folgt eine Lücke und anschließend der 6. und 7. Januar. Wir erwarten zwei Folgen: eine 3-tägige und eine 2-tägige Folge.
SELECT * FROM logins ORDER BY user_id, login_date;
-- user_id | login_date
-- 1 | 2024-01-01
-- 1 | 2024-01-02
-- 1 | 2024-01-03
-- 1 | 2024-01-06
-- 1 | 2024-01-07Die zentrale Erkenntnis
Hier ist der Kniff, der jedes Problem mit aufeinanderfolgenden Tagen erschließt. Wenn Sie die Zeilen nach Datum sortieren und jeder eine fortlaufende Zeilennummer zuweisen, bleibt für jede Folge aufeinanderfolgender Tage die Differenz zwischen Datum und Zeilennummer konstant.
Warum? Sowohl das Datum als auch die Zeilennummer erhöhen sich an jedem aufeinanderfolgenden Tag genau um 1, daher ändert sich ihre Differenz nicht. Bei einer Lücke springt das Datum weiter, die Zeilennummer jedoch nicht — dadurch wird die Konstanz unterbrochen und eine neue Gruppe begonnen.
Die Differenz nachvollziehen
Gehen wir das für Benutzer 1 von Hand durch. ROW_NUMBER zählt 1, 2, 3, 4, 5. Subtrahieren Sie die Zeilennummer (als Anzahl von Tagen) vom Datum und beobachten Sie das Ergebnis.
- 1. Jan. − 1 = 31. Dez.
- 2. Jan. − 2 = 31. Dez.
- 3. Jan. − 3 = 31. Dez.
- 6. Jan. − 4 = 2. Jan.
- 7. Jan. − 5 = 2. Jan.
Die ersten drei ergeben den 31. Dez.; die letzten beiden den 2. Jan. Dieser gemeinsame Ankerwert ist unser Gruppenschlüssel.
ROW_NUMBER hinzufügen
Der erste konkrete Schritt besteht darin, jeder Zeile eine Zeilennummer zuzuweisen, partitioniert nach Benutzer, damit sich Folgen nie über Benutzergrenzen hinweg erstrecken, und nach Datum sortiert.
PARTITION BY user_id setzt den Zähler für jeden Benutzer zurück; ORDER BY login_date stellt sicher, dass die Reihenfolge dem Kalender folgt.
SELECT
user_id,
login_date,
ROW_NUMBER() OVER (
PARTITION BY user_id
ORDER BY login_date
) AS rn
FROM logins;Den Gruppenanker berechnen
Subtrahieren Sie nun rn Tage von login_date. In PostgreSQL können Sie eine ganzzahlige Anzahl von Tagen direkt von einem Datum subtrahieren. Das Ergebnis ist der konstante Anker, der jede Insel identifiziert.
Beachten Sie, dass wir im selben SELECT, in dem der Alias rn definiert wird, nicht auf ihn verweisen können — deshalb verpacken wir die vorherige Abfrage zunächst in eine CTE oder Unterabfrage.
WITH numbered AS (
SELECT
user_id,
login_date,
ROW_NUMBER() OVER (
PARTITION BY user_id ORDER BY login_date
) AS rn
FROM logins
)
SELECT
user_id,
login_date,
login_date - rn AS grp
FROM numbered;Die Inseln gruppieren
Mit dem Anker hat jede aufeinanderfolgende Folge denselben Wert grp. Gruppieren Sie nach user_id und grp und aggregieren Sie anschließend, um Beginn, Ende und Länge jeder Folge zu erhalten.
MIN(login_date)— erster Tag der FolgeMAX(login_date)— letzter Tag der FolgeCOUNT(*)— Anzahl der Tage in der Folge
WITH numbered AS (
SELECT user_id, login_date,
ROW_NUMBER() OVER (
PARTITION BY user_id ORDER BY login_date
) AS rn
FROM logins
)
SELECT
user_id,
MIN(login_date) AS streak_start,
MAX(login_date) AS streak_end,
COUNT(*) AS streak_len
FROM numbered
GROUP BY user_id, login_date - rn
ORDER BY user_id, streak_start;Unterschiede zwischen SQL-Dialekten
Die Syntax der Datumsarithmetik variiert. Erwähnen Sie dies in Interviews, um Ihre breiten Kenntnisse zu zeigen.
- PostgreSQL:
login_date - rn(Datum minus ganzzahlige Anzahl von Tagen) - MySQL:
DATE_SUB(login_date, INTERVAL rn DAY) - SQL Server:
DATEADD(day, -rn, login_date)
Die Logik ist identisch; nur die Funktionsnamen ändern sich. Das portable Denkmodell lautet: „Verschieben Sie jedes Datum um seine Position rückwärts, sodass eine lückenlose Folge auf einen einzigen konstanten Wert abgebildet wird.“
-- SQL Server version of the anchor
DATEADD(day, -1 * rn, login_date) AS grpWarum kein Self-Join?
Ein Interviewer fragt möglicherweise, warum Sie einen Self-Join wie l1.login_date = l2.login_date + 1 vermieden haben. Nennen Sie folgende Gründe:
- Ein Self-Join prüft nur die Nachbarschaft, nicht die vollständige Folge — zum Zusammensetzen vollständiger Folgen ist weiterhin eine Gruppierung erforderlich.
- Ohne gute Indizes kann es zu einer Vervielfachung der Zeilen kommen, und die Komplexität beträgt O(n²).
- Die Methode mit Zeilennummern ist ein einziger geordneter Durchlauf und daher deutlich besser skalierbar.
Fensterfunktionen sind für diese Probleme die moderne und erwartete Lösung.
Duplikate berücksichtigen
Die gesamte Technik setzt eine Zeile pro Benutzer und Tag voraus. Wenn die Quelle mehrere Logins pro Tag enthält, erhalten zwei Zeilen mit demselben Datum unterschiedliche Zeilennummern, wodurch der Anker verfälscht wird.
Sichern Sie sich dagegen ab, indem Sie zunächst deduplizieren — wandeln Sie Zeitstempel in Daten um und verwenden Sie DISTINCT, oder nutzen Sie DENSE_RANK für das Datum statt ROW_NUMBER, sodass gleiche Daten dieselbe Nummer erhalten.
WITH days AS (
SELECT DISTINCT user_id, login_ts::date AS login_date
FROM raw_logins
)
SELECT * FROM days;Die vollständige Lösung
Wenn Sie alle Teile zusammenfügen, erhalten Sie eine klare, interviewtaugliche Antwort, die jede Folge aufeinanderfolgender Tage mit Beginn, Ende und Länge auflistet.
Dieses Grundgerüst — Duplikate entfernen, nummerieren, subtrahieren, gruppieren — löst fast jede Frage zu „aufeinanderfolgenden“ Werten, die Ihnen gestellt wird.
WITH days AS (
SELECT DISTINCT user_id, login_ts::date AS login_date
FROM raw_logins
),
numbered AS (
SELECT user_id, login_date,
ROW_NUMBER() OVER (
PARTITION BY user_id ORDER BY login_date
) AS rn
FROM days
)
SELECT user_id,
MIN(login_date) AS streak_start,
MAX(login_date) AS streak_end,
COUNT(*) AS streak_len
FROM numbered
GROUP BY user_id, login_date - rn
ORDER BY user_id, streak_start;Kurzer Test
Testen Sie, ob Sie den zentralen Kniff verstanden haben.
Zusammenfassung
Sie haben das grundlegende Muster für aufeinanderfolgende Tage gelernt:
- Deduplizieren, sodass eine Zeile pro Benutzer und Tag verbleibt.
- ROW_NUMBER, nach Datum sortiert und nach Benutzer partitioniert.
- Die Zeilennummer vom Datum subtrahieren, um einen konstanten Anker pro Folge zu erhalten.
- Nach dem Anker GROUP BY verwenden und für Beginn, Ende und Länge aggregieren.
Dieses Grundgerüst für Lücken und Inseln skaliert in einem einzigen Durchlauf und ist Self-Joins überlegen. Als Nächstes verwenden Sie es, um die längste Folge pro Benutzer zu berechnen.
Häufig gestellte Fragen
Ist die Lektion „Aufeinanderfolgende Kalendertage erkennen“ kostenlos?
Ja — der vollständige Text von „Aufeinanderfolgende Kalendertage erkennen“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Coding Interview Prep-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Coding Interview Prep-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Aufeinanderfolgende Kalendertage erkennen“?
Datumsarithmetik und Zeilennummern verwenden, um durchgehende Tagesfolgen zu finden Du übst Coding Interview Prep mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um Coding Interview Prep zu starten?
Keine Vorkenntnisse erforderlich. Coding Interview Prep auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 1 von 4.
Wie lange dauert die Lektion „Aufeinanderfolgende Kalendertage erkennen“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser Coding Interview Prep-Lektion Code schreiben und ausführen?
Ja. Jede Coding Interview Prep-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Aufeinanderfolgende Kalendertage erkennen
- Längste Serie pro Benutzer
- N aufeinanderfolgende Zeilen mit erfüllter Bedingung
- Aktuelle aktive Serie bis heute