0Pricing
SQL Interview Prep · Leçon

Détecter les jours consécutifs du calendrier

Utiliser l’arithmétique des dates et les numéros de ligne pour trouver les séries de jours ininterrompues

Détecter les jours consécutifs du calendrier est une leçon SQL Interview Prep gratuite sur CoddyKit. Ceci est la leçon 1 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage SQL Interview Prep, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours SQL Interview Prep comprend 4 leçons au total.

Le cadre de l'entretien

Les personnes qui mènent les entretiens apprécient les questions sur les séries, car elles révèlent si vous comprenez réellement les fonctions de fenêtrage et l'arithmétique des dates. Une consigne typique : « Étant donné une table contenant les dates de connexion des utilisateurs, trouvez chaque série ininterrompue de jours calendaires consécutifs. »

Le réflexe naïf consiste à effectuer une auto-jointure comparant chaque ligne à la suivante, mais cette approche devient énorme sur les grandes tables et s'exprime difficilement. La réponse professionnelle utilise la technique des lacunes et des îlots. Dans cette leçon, vous apprendrez à détecter proprement les jours consécutifs avec des numéros de ligne et la soustraction de dates.

Les données d'exemple

Tout au long de cette leçon, nous utilisons une table logins contenant une ligne par utilisateur et par jour où il a été actif. Les doublons sont supposés avoir déjà été supprimés (une connexion par jour calendaire).

  • user_id — l'utilisateur qui s'est connecté
  • login_date — une valeur de DATE

Pour l'utilisateur 1, les dates sont les 1er, 2 et 3 janvier, puis une interruption, puis les 6 et 7 janvier. Nous attendons deux séries : une série de 3 jours et une de 2 jours.

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-07

L'idée centrale

Voici l'astuce qui permet de résoudre tout problème portant sur des jours consécutifs. Si vous ordonnez les lignes par date et attribuez à chacune un numéro de ligne séquentiel, alors, pour toute série de jours consécutifs, la différence entre la date et le numéro de ligne reste constante.

Pourquoi ? La date et le numéro de ligne augmentent tous deux exactement de 1 chaque jour consécutif, leur différence ne change donc pas. Lorsqu'une interruption apparaît, la date avance brusquement, mais pas le numéro de ligne : la constante est rompue et un nouveau groupe commence.

Observer la différence

Examinons-le à la main pour l'utilisateur 1. ROW_NUMBER compte 1, 2, 3, 4, 5. Soustrayez le numéro de ligne (en jours) de la date et observez le résultat.

  • 1er janvier − 1 = 31 décembre
  • 2 janvier − 2 = 31 décembre
  • 3 janvier − 3 = 31 décembre
  • 6 janvier − 4 = 2 janvier
  • 7 janvier − 5 = 2 janvier

Les trois premières lignes partagent la valeur du 31 décembre ; les deux dernières, celle du 2 janvier. Cette valeur d'ancrage commune est notre clé de groupe.

Ajout de ROW_NUMBER

La première étape concrète consiste à associer un numéro de ligne, partitionné par utilisateur afin que les séries ne franchissent jamais les limites entre utilisateurs, puis ordonné par date.

PARTITION BY user_id redémarre le compteur pour chaque utilisateur ; ORDER BY login_date garantit que la séquence suit le calendrier.

SELECT
  user_id,
  login_date,
  ROW_NUMBER() OVER (
    PARTITION BY user_id
    ORDER BY login_date
  ) AS rn
FROM logins;

Calcul de l'ancre de groupe

Soustrayez maintenant rn jours de login_date. Dans PostgreSQL, vous pouvez soustraire directement d'une date un nombre entier de jours. Le résultat est l'ancre constante qui identifie chaque îlot.

Notez que nous ne pouvons pas faire référence à l'alias rn dans le même SELECT que celui qui le définit ; nous devons donc d'abord placer la requête précédente dans une CTE ou une sous-requête.

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;

Regroupement des îlots

Une fois l'ancre obtenue, chaque série consécutive partage la même valeur grp. Regroupez par user_id et grp, puis agrégez pour obtenir le début, la fin et la longueur de chaque série.

  • MIN(login_date) — premier jour de la série
  • MAX(login_date) — dernier jour de la série
  • COUNT(*) — nombre de jours de la série
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;

Différences entre les dialectes

La syntaxe de l'arithmétique des dates varie. Mentionnez-le lors des entretiens pour montrer l'étendue de vos connaissances.

  • PostgreSQL : login_date - rn (date moins un nombre entier de jours)
  • MySQL : DATE_SUB(login_date, INTERVAL rn DAY)
  • serveur SQL : DATEADD(day, -rn, login_date)

La logique est identique ; seuls les noms de fonctions changent. Le modèle mental portable consiste à « décaler chaque date vers l'arrière selon sa position afin qu'une série continue se réduise à une seule constante ».

-- SQL Server version of the anchor
DATEADD(day, -1 * rn, login_date) AS grp

Pourquoi pas d'auto-jointure ?

La personne qui mène l'entretien peut vous demander pourquoi vous avez évité une auto-jointure telle que l1.login_date = l2.login_date + 1. Voici les raisons à donner :

  • Une auto-jointure ne teste que la contiguïté, et non la série complète ; il faut encore regrouper pour assembler les séries entières.
  • Elle peut multiplier les lignes et être en O(n²) sans bons index.
  • La méthode des numéros de ligne effectue un seul passage ordonné et s'adapte bien mieux aux grandes quantités de données.

Les fonctions de fenêtrage sont la réponse moderne attendue pour ces problèmes.

Se prémunir contre les doublons

Toute la technique suppose une ligne par utilisateur et par jour. Si la source contient plusieurs connexions par jour, deux lignes ayant la même date reçoivent des numéros de ligne différents, ce qui fausse l'ancre.

Pour y remédier, dédoublonnez d'abord — convertissez les horodatages en dates et prenez DISTINCT, ou utilisez DENSE_RANK sur la date plutôt que ROW_NUMBER afin que les dates identiques partagent un même numéro.

WITH days AS (
  SELECT DISTINCT user_id, login_ts::date AS login_date
  FROM raw_logins
)
SELECT * FROM days;

La solution complète

En rassemblant tous les éléments, vous obtenez une réponse claire, prête pour l'entretien, qui répertorie chaque série de jours consécutifs avec son début, sa fin et sa longueur.

Cette même structure — dédoublonner, numéroter, soustraire, regrouper — résout presque toutes les questions portant sur les éléments « consécutifs » que l'on pourrait vous poser.

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;

Vérification rapide

Vérifiez votre compréhension de l'astuce centrale.

Récapitulatif

Vous avez appris le modèle fondamental des jours consécutifs :

  • Dédoublonnez pour obtenir une ligne par utilisateur et par jour.
  • ROW_NUMBER ordonné par date et partitionné par utilisateur.
  • Soustrayez le numéro de ligne de la date pour obtenir une ancre constante par série.
  • GROUP BY sur l'ancre, puis agrégez pour obtenir le début, la fin et la longueur.

Cette structure des lacunes et des îlots s'adapte en un seul passage et est plus efficace que les auto-jointures. Vous l'utiliserez ensuite pour calculer la plus longue série par utilisateur.

Questions Fréquemment Posées

La leçon « Détecter les jours consécutifs du calendrier » est-elle gratuite ?

Oui — le texte complet de « Détecter les jours consécutifs du calendrier » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours SQL Interview Prep, passe à CoddyKit PRO. Le cours SQL Interview Prep comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Détecter les jours consécutifs du calendrier » ?

Utiliser l’arithmétique des dates et les numéros de ligne pour trouver les séries de jours ininterrompues Tu pratiques SQL Interview Prep avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer SQL Interview Prep ?

Aucune expérience préalable n'est requise. SQL Interview Prep sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 1 sur 4.

Combien de temps prend la leçon « Détecter les jours consécutifs du calendrier » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon SQL Interview Prep ?

Oui. Chaque leçon SQL Interview Prep inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Détecter les jours consécutifs du calendrier
  2. Plus longue série par utilisateur
  3. N lignes consécutives remplissant une condition
  4. Série active en cours aujourd’hui
← Retour à SQL Interview Prep