# Comment réaliser une comparaison de date en SQL
La manipulation des dates représente l’un des défis quotidiens les plus fréquents pour tout développeur travaillant avec des bases de données relationnelles. Que vous analysiez des tendances temporelles, filtriez des enregistrements selon des périodes spécifiques ou calculiez des intervalles entre événements, maîtriser les techniques de comparaison de dates en SQL devient rapidement indispensable. Les systèmes de gestion de bases de données modernes offrent une panoplie d’outils sophistiqués pour traiter ces opérations, mais la diversité des approches selon les différents SGBD peut parfois dérouter même les professionnels expérimentés. Comprendre les nuances entre les types de données temporelles, savoir quand utiliser une fonction plutôt qu’un opérateur, et optimiser vos requêtes pour maintenir des performances acceptables constituent des compétences essentielles dans votre arsenal technique.
Les opérateurs de comparaison SQL pour manipuler les dates
Les opérateurs de comparaison constituent la fondation même de toute manipulation temporelle en SQL. Contrairement aux idées reçues, ces opérateurs ne se limitent pas aux valeurs numériques et fonctionnent parfaitement avec les types de données temporelles. Leur compréhension approfondie vous permettra d’éviter les pièges classiques qui génèrent des résultats inattendus, notamment lors de la comparaison de dates incluant des composants horaires. La précision dans l’utilisation de ces opérateurs détermine directement la fiabilité de vos analyses temporelles.
Syntaxe des opérateurs =, <, >, <=, >= et <> avec DATE et DATETIME
L’opérateur d’égalité = vérifie la correspondance exacte entre deux valeurs temporelles, incluant tous les composants de la date et de l’heure. Cette précision peut surprendre lorsque vous comparez une colonne DATETIME contenant des informations horaires avec une simple date. Par exemple, si votre colonne stocke ‘2024-01-15 14:30:00’ et que vous filtrez avec WHERE date_colonne = '2024-01-15', aucun résultat ne sera retourné car la comparaison inclut implicitement ‘2024-01-15 00:00:00’. Cette particularité explique pourquoi de nombreuses requêtes semblant logiques ne retournent aucune donnée.
Les opérateurs de comparaison <, >, <= et = suivent naturellement l’ordre chronologique. Une date antérieure sera toujours considérée comme « inférieure » à une date postérieure, ce qui rend ces opérateurs intuitifs pour définir des plages temporelles. L’opérateur <> ou != permet d’exclure une date spécifique de vos résultats. Lorsque vous travaillez avec des colonnes DATETIME, n’oubliez jamais que la comparaison s’effectue jusqu’à la milliseconde selon le type exact utilisé par votre SGBD.
L’opérateur BETWEEN pour filtrer les intervalles temporels
L’opérateur BETWEEN simplifie considérablement la syntaxe des requêtes nécessitant des plages temporelles. Au lieu d’écrire WHERE date_colonne >= '2024-01-01' AND date_colonne <= '2024-12-31', vous pouvez utiliser WHERE date_colonne BETWEEN '2024-01-01' AND '2024-12-31'. Attention cependant : BETWEEN est inclusif des deux bornes, ce qui signifie que les valeurs exactement égales aux
bornes seront également incluses dans le résultat. Cette caractéristique est particulièrement importante lorsqu’une composante horaire est présente : une condition comme BETWEEN '2024-01-01' AND '2024-01-31' n’inclura que les enregistrements jusqu’à ‘2024-01-31 00:00:00’. Pour couvrir toute la journée, il est souvent préférable de définir la borne supérieure au premier jour du mois suivant : WHERE date_colonne >= '2024-01-01' AND date_colonne < '2024-02-01'.
Une bonne pratique pour la comparaison de dates en SQL consiste d’ailleurs à travailler avec des intervalles demi-ouverts [début, fin[ (inclusif sur la borne basse, exclusif sur la borne haute). Cette approche évite les erreurs liées aux millisecondes ou aux changements de précision selon les types de données. Elle est particulièrement utile lorsque vous enchaînez des périodes contiguës comme des jours, des semaines ou des mois, car elle garantit l’absence de trous ou de chevauchements dans les plages temporelles.
Combinaison des opérateurs AND et OR dans les clauses WHERE temporelles
Lorsque l’on commence à enchaîner plusieurs conditions temporelles avec AND et OR, la lisibilité devient vite un enjeu majeur. Pour filtrer, par exemple, les commandes passées en 2023 mais uniquement les week-ends, vous pourriez écrire : WHERE order_date >= '2023-01-01' AND order_date < '2024-01-01' AND (DAYOFWEEK(order_date) = 1 OR DAYOFWEEK(order_date) = 7) selon le SGBD utilisé. Les parenthèses jouent ici un rôle crucial pour définir explicitement l’ordre d’évaluation des conditions.
Une erreur fréquente lors de la comparaison de dates en SQL consiste à oublier ces parenthèses, entraînant des résultats logiques incorrects. Par exemple, WHERE order_date >= '2023-01-01' AND order_date < '2024-01-01' OR status = 'TEST' ne signifie pas « toutes les commandes de 2023 sauf celles en statut TEST », mais bien « toutes les commandes de 2023, plus toutes les commandes avec status = ‘TEST’ quelle que soit la date ». Pour éviter ces pièges, nous vous recommandons de toujours clarifier vos groupes de conditions temporelles avec des parenthèses explicites.
Gestion des valeurs NULL avec IS NULL et IS NOT NULL sur les colonnes de dates
Les colonnes de type DATE ou DATETIME peuvent contenir des valeurs NULL lorsqu’une information temporelle n’est pas encore connue (date de livraison estimée, date de clôture, etc.). Comparer directement ces valeurs NULL avec les opérateurs classiques = ou < ne donnera jamais de résultat, car en SQL, NULL représente une absence d’information, non comparable. Pour identifier explicitement ces enregistrements, il faut utiliser les opérateurs IS NULL et IS NOT NULL.
Dans une requête métier, vous pourriez par exemple filtrer toutes les commandes encore ouvertes avec : WHERE shipped_at IS NULL. À l’inverse, si vous souhaitez comparer uniquement les dates effectivement renseignées, pensez à exclure les valeurs NULL via WHERE closed_at IS NOT NULL AND closed_at < CURRENT_DATE. Cette distinction est essentielle pour éviter de fausser vos analyses temporelles en mélangeant événements datés et événements encore en attente de date.
Les fonctions natives de comparaison de dates selon les SGBD
Au-delà des opérateurs de base, chaque moteur SQL propose des fonctions dédiées à la comparaison de dates. Elles permettent de calculer des différences, d’extraire des composantes temporelles ou de manipuler des intervalles. La difficulté vient du fait qu’il n’existe pas de standard unique : MySQL, PostgreSQL, SQL Server ou Oracle ont chacun leurs propres fonctions et signatures. Pour écrire des requêtes portables, ou simplement pour éviter les erreurs de syntaxe, il est donc indispensable de connaître les grandes familles de fonctions disponibles dans votre SGBD.
DATEDIFF et TIMESTAMPDIFF dans MySQL et MariaDB
Dans MySQL et MariaDB, la fonction DATEDIFF() permet de comparer deux dates en retournant le nombre de jours entiers qui les séparent : SELECT DATEDIFF('2024-02-10', '2024-02-01'); -- retourne 9. Elle est particulièrement utile pour calculer une ancienneté en jours, mesurer un délai de traitement ou identifier les enregistrements en retard. Notez qu’elle ignore la partie horaire : seules les dates sont prises en compte pour la différence.
Pour des comparaisons de dates plus fines, il est préférable d’utiliser TIMESTAMPDIFF(), qui accepte une unité de temps comme premier paramètre. Par exemple, TIMESTAMPDIFF(HOUR, start_time, end_time) calcule le nombre d’heures entre deux DATETIME, tandis que TIMESTAMPDIFF(MINUTE, ...) ou SECOND affinent encore la précision. Cette fonction devient un outil clé dans les rapports de performance (temps moyen de réponse, durée des sessions, etc.) en vous évitant des manipulations manuelles complexes.
DATE_PART et EXTRACT pour PostgreSQL
PostgreSQL met à disposition deux fonctions très proches pour travailler avec les dates : DATE_PART() et EXTRACT(). Toutes deux permettent d’extraire des composantes spécifiques d’une date ou d’un timestamp, par exemple SELECT DATE_PART('day', order_date) ou EXTRACT(DAY FROM order_date). Pour la comparaison de dates en SQL, ces fonctions sont pratiques lorsque vous devez filtrer sur un mois ou une année indépendamment du reste de la date.
Par exemple, pour récupérer toutes les ventes réalisées au mois de mars, quelle que soit l’année, vous pouvez écrire : WHERE EXTRACT(MONTH FROM order_date) = 3. De même, pour construire des rapports mensuels ou trimestriels, il est courant d’utiliser EXTRACT(YEAR FROM ...) et EXTRACT(QUARTER FROM ...). Gardez toutefois à l’esprit que l’utilisation de ces fonctions dans la clause WHERE peut empêcher l’optimiseur d’utiliser un index sur la colonne de date, ce qui aura un impact sur les performances pour les grandes tables.
DATEADD et DATEDIFF sous SQL server et T-SQL
Sous SQL Server, la combinaison DATEDIFF() et DATEADD() constitue le socle de la comparaison de dates. La fonction DATEDIFF(datepart, startdate, enddate) retourne un entier correspondant au nombre de limites de datepart traversées entre deux valeurs, qu’il s’agisse de jours, d’heures ou même de millisecondes. Par exemple, SELECT DATEDIFF(day, '2024-01-01', '2024-01-10'); -- 9. On l’utilise souvent pour calculer des délais, des anciens nets ou valider des contraintes métiers.
La fonction DATEADD(), quant à elle, permet d’ajouter ou de soustraire un intervalle temporel à une date. Pour récupérer toutes les lignes créées lors des 7 derniers jours, vous pouvez par exemple écrire : WHERE created_at >= DATEADD(day, -7, GETDATE()). En combinant DATEDIFF et DATEADD, il est possible de construire des filtres temporels dynamiques très puissants (début de mois en cours, dernière heure glissante, etc.), tout en restant dans un langage SQL natif facile à maintenir.
TRUNC et MONTHS_BETWEEN dans oracle database
Oracle Database offre une approche légèrement différente avec la fonction TRUNC() appliquée aux dates. Elle permet de tronquer une date au jour, au mois ou à l’année, en supprimant les composantes plus fines. Par exemple, TRUNC(order_date) ramène toutes les valeurs à minuit, tandis que TRUNC(order_date, 'MM') renvoie le premier jour du mois. Cette fonction est très utile pour la comparaison de dates « à la journée » dans Oracle, sans tenir compte de l’heure.
La fonction MONTHS_BETWEEN(date1, date2) calcule, elle, le nombre de mois (possiblement décimaux) entre deux dates. Vous pouvez ainsi mesurer précisément l’ancienneté d’un client en mois, ou la durée moyenne d’un contrat. Un exemple typique : SELECT MONTHS_BETWEEN(SYSDATE, hire_date) AS anciennete_mois FROM employees;. Couplée à ADD_MONTHS(), elle permet de mettre en œuvre des règles métier complexes impliquant des échéances mensuelles ou trimestrielles.
Conversion et formatage des types de données temporelles
Dans les applications réelles, les dates ne se présentent pas toujours sous la forme de beaux DATE ou TIMESTAMP. Elles arrivent parfois en VARCHAR, issues d’un fichier CSV, d’une API ou d’un formulaire utilisateur. Pour réaliser une comparaison de date en SQL fiable, il est alors impératif de convertir ces chaînes en types temporels avant de les comparer. C’est là qu’entrent en jeu les fonctions de conversion et de formatage.
CAST et CONVERT pour transformer VARCHAR en DATE
La conversion explicite via CAST() est supportée par la plupart des SGBD. Sur SQL Server, par exemple, CAST('2024-02-01' AS DATE) permet de transformer une chaîne en véritable date. La fonction CONVERT() offre quant à elle plus de contrôle sur le style de format, avec un troisième paramètre indiquant le format attendu (par exemple 103 pour dd/mm/yyyy). Cette précision devient indispensable lorsque vos données sources ne respectent pas le format ISO YYYY-MM-DD.
Un piège courant consiste à comparer directement une colonne DATE avec une colonne VARCHAR contenant une date, en s’en remettant aux conversions implicites du SGBD. Non seulement le comportement peut varier selon la configuration régionale, mais cela peut aussi entraîner des erreurs subtiles. La bonne pratique pour la comparaison de dates en SQL est de convertir toujours les chaînes en types temporels explicites dans vos requêtes, via CAST ou CONVERT, plutôt que l’inverse.
TO_DATE et STR_TO_DATE selon les dialectes SQL
Dans Oracle, TO_DATE() est la fonction de référence pour convertir une chaîne en date en spécifiant un masque de format : TO_DATE('31/12/2024', 'DD/MM/YYYY'). Ce masque évite toute ambiguïté entre jours et mois, en particulier dans les environnements internationaux. Vous pouvez également préciser la langue pour les noms de mois via un troisième paramètre NLS, ce qui est pratique pour parser des chaînes comme « 15-janv-2024 ».
MySQL et MariaDB utilisent STR_TO_DATE() avec une logique proche : STR_TO_DATE('31/12/2024 23:59', '%d/%m/%Y %H:%i'). Cette fonction prend en charge un large éventail de formats, ce qui permet de normaliser des données historiques issues de systèmes hétérogènes. Là encore, il est préférable d’appliquer la conversion dans une étape de préparation (ETL, vue matérialisée, colonne calculée) plutôt que dans chaque clause WHERE, afin de préserver les performances et la simplicité des filtres temporels.
Gestion des fuseaux horaires avec TIMESTAMP et TIMESTAMPTZ
Dès que vos applications sont utilisées dans plusieurs pays, la gestion des fuseaux horaires devient un enjeu critique. Stocker un simple DATETIME local sans information de fuseau peut conduire à des comparaisons erronées, notamment lors des changements d’heure saisonniers. Pour éviter ces pièges, de nombreux SGBD proposent des types dédiés comme TIMESTAMP WITH TIME ZONE (Oracle) ou TIMESTAMPTZ (PostgreSQL).
La bonne pratique consiste souvent à stocker toutes les dates en UTC, puis à convertir à l’affichage dans le fuseau de l’utilisateur. En PostgreSQL, par exemple, created_at AT TIME ZONE 'Europe/Paris' permet de projeter un instant donné dans un fuseau spécifique. Lorsque vous réalisez une comparaison de dates en SQL dans un contexte multi-fuseaux, assurez-vous que toutes les valeurs sont ramenées au même référentiel temporel (généralement UTC) avant de les comparer, sous peine d’obtenir des décalages d’une heure ou plus.
Comparaison de dates avec extraction de composants temporels
Il arrive fréquemment que l’on souhaite comparer des dates non pas sur leur valeur complète, mais sur un composant particulier : année, mois, jour, ou même heure. Plutôt que de convertir les dates en texte, il est préférable d’utiliser les fonctions dédiées proposées par votre SGBD pour extraire ces composants et construire des conditions lisibles.
YEAR, MONTH et DAY pour isoler les composants de date
La plupart des moteurs SQL proposent des fonctions comme YEAR(), MONTH() et DAY() (ou leurs équivalents via EXTRACT()) pour isoler les composantes d’une date. Vous pouvez ainsi filtrer « toutes les commandes de l’année 2023 » avec WHERE YEAR(order_date) = 2023 ou « tous les anniversaires en avril » avec WHERE MONTH(birth_date) = 4. Pour la comparaison de dates en SQL au niveau annuel ou mensuel, ces fonctions sont simples et intuitives.
Néanmoins, leur utilisation directe dans les clauses WHERE sur des colonnes volumineuses peut nuire aux performances, car elle empêche souvent l’utilisation d’un index sur la date complète. Une alternative plus performante consiste à reformuler la condition sous forme de plage : WHERE order_date >= '2023-01-01' AND order_date < '2024-01-01' plutôt que YEAR(order_date) = 2023. Cette approche illustre bien le compromis constant entre lisibilité du code SQL et optimisation des comparaisons de dates.
HOUR, MINUTE et SECOND dans les requêtes DATETIME
Lorsque la composante horaire joue un rôle clé (analyses de trafic, logs applicatifs, mesures de performance), il devient utile d’isoler également les heures, minutes et secondes. MySQL, par exemple, propose les fonctions HOUR(), MINUTE() et SECOND() qui extraient ces parties à partir d’un DATETIME. Une requête typique pourrait être : WHERE HOUR(event_time) BETWEEN 9 AND 18 pour ne conserver que les événements survenus pendant les heures ouvrées.
Dans les systèmes plus avancés, comme PostgreSQL, il est également possible d’utiliser EXTRACT(HOUR FROM event_time). Vous pourriez, par exemple, comparer la distribution d’événements entre la matinée et l’après-midi pour optimiser vos ressources techniques. Ici encore, si vous appliquez ces fonctions à de très grands volumes, pensez à tester l’impact sur les plans d’exécution et, si nécessaire, à créer des colonnes dérivées indexées pour accélérer les comparaisons.
DAYOFWEEK et WEEKDAY pour les analyses hebdomadaires
Les analyses hebdomadaires, comme la répartition des ventes par jour de la semaine, nécessitent souvent d’identifier le jour correspondant à une date donnée. MySQL offre par exemple DAYOFWEEK() et WEEKDAY(), qui renvoient respectivement un indice basé sur le dimanche ou le lundi. D’autres SGBD proposent des fonctions équivalentes via EXTRACT(DOW FROM date) (PostgreSQL) ou des formules utilisant DATEPART() (SQL Server).
Pour la comparaison de dates en SQL à l’échelle de la semaine, ces fonctions permettent de répondre à des questions comme : « Quel est le jour de la semaine le plus rentable ? » ou « Les pannes se produisent-elles plus souvent le lundi matin ? ». Il suffit ensuite d’agréger par ce jour et de comparer les résultats entre eux, en jouant éventuellement avec des fonctions analytiques pour lisser les tendances sur plusieurs semaines.
QUARTER et WEEK pour les rapports périodiques
Les directions financières et marketing s’appuient souvent sur des rapports trimestriels ou hebdomadaires. Pour les alimenter, les fonctions QUARTER() et WEEK() (ou leurs équivalents DATEPART(quarter, ...) sous SQL Server, EXTRACT(QUARTER FROM ...) sous PostgreSQL) sont très utiles. Elles permettent de grouper les données par période standardisée sans avoir à gérer manuellement des plages de dates complexes.
Par exemple, une requête comme SELECT QUARTER(invoice_date) AS trimestre, SUM(amount) FROM invoices GROUP BY QUARTER(invoice_date) vous donnera en un clin d’œil le chiffre d’affaires par trimestre. Pour la comparaison de dates en SQL sur plusieurs années, vous pouvez combiner année et trimestre (EXTRACT(YEAR FROM date), EXTRACT(QUARTER FROM date)) et suivre l’évolution de vos indicateurs périodiques dans le temps.
Optimisation des performances avec les index temporels
Dès que les volumes de données augmentent, la comparaison de dates en SQL peut devenir un goulet d’étranglement si les requêtes ne sont pas indexées correctement. Les colonnes de type DATE ou TIMESTAMP sont souvent utilisées dans les clauses WHERE ou JOIN, ce qui en fait de bonnes candidates pour la création d’index. Cependant, il ne suffit pas de « mettre un index partout » : il faut comprendre comment l’optimiseur exploite ces structures.
Création d’index b-tree sur les colonnes DATE et TIMESTAMP
Les index de type B-tree, par défaut dans la plupart des SGBD, sont particulièrement bien adaptés aux colonnes temporelles. Ils permettent de rechercher rapidement toutes les lignes dont la date se situe dans un intervalle donné, ce qui correspond à la majorité des cas d’usage métiers (dernière semaine, dernier mois, période de facturation, etc.). Sur une table de logs contenant des millions de lignes, un index sur created_at peut réduire dramatiquement le temps de réponse d’une requête filtrant sur une plage de dates.
Avant de créer un index sur une colonne temporelle, posez-vous toutefois deux questions : la colonne est-elle fréquemment utilisée dans les filtres ou les jointures ? Quelle est la sélectivité des conditions typiques (un jour, un mois, une année) ? Un index sera d’autant plus efficace que les filtres sont sélectifs. Dans certains cas, un index composite incluant la date et une autre colonne très discriminante (par exemple (created_at, user_id)) offrira de meilleures performances globales.
Éviter les fonctions dans WHERE pour préserver l’utilisation des index
Un des pièges les plus fréquents en optimisation SQL consiste à appliquer des fonctions directement sur une colonne indexée dans la clause WHERE. Par exemple, WHERE DATE(order_date) = '2024-02-01' ou WHERE EXTRACT(MONTH FROM order_date) = 2 forcent le SGBD à calculer la fonction pour chaque ligne, ce qui rend l’index difficilement exploitable. Résultat : un parcours séquentiel de la table et des temps de réponse qui explosent.
Pour préserver l’utilisation des index temporels, la meilleure approche est de réécrire ces conditions en termes de plages de dates. Ainsi, la condition précédente peut devenir WHERE order_date >= '2024-02-01' AND order_date < '2024-02-02'. Cette simple transformation permet souvent à l’optimiseur de recourir à un index range scan au lieu d’un full scan, ce qui, sur des millions de lignes, fait toute la différence.
Utilisation de colonnes calculées et index sur expressions
Dans certains cas, vous avez absolument besoin de filtrer sur une partie de la date (par exemple le mois ou le jour de la semaine) pour vos rapports. Plutôt que d’appliquer une fonction à la volée dans chaque requête, vous pouvez créer une colonne calculée persistante qui stocke cette information dérivée. SQL Server permet par exemple de définir computed columns basées sur DATEPART(...), puis d’indexer ces colonnes.
D’autres SGBD, comme PostgreSQL ou Oracle, offrent la possibilité de créer des index sur expression, par exemple CREATE INDEX idx_orders_year_month ON orders ((EXTRACT(YEAR FROM order_date)), (EXTRACT(MONTH FROM order_date)));. Ainsi, vous conservez la flexibilité d’écrire vos requêtes avec ces composants temporels tout en bénéficiant des performances d’un index dédié. C’est un compromis puissant entre expressivité des filtres et efficacité de la comparaison de dates en SQL.
Cas pratiques avancés de comparaison de dates en SQL
Une fois les bases maîtrisées, la comparaison de dates en SQL devient un véritable outil d’analyse avancée. Vous pouvez calculer des anciennetés, modéliser des jours ouvrés, créer des plages dynamiques ou détecter des chevauchements de périodes. Ces cas d’usage, fréquents en reporting et en BI, illustrent la puissance combinée des opérateurs temporels, des fonctions de dates et des window functions.
Calcul d’ancienneté et différence en jours ouvrés avec CASE WHEN
Calculer l’ancienneté d’un contrat ou d’un employé en jours calendaires est simple avec DATEDIFF() ou DATEDIFF(day, ...). Mais comment tenir compte uniquement des jours ouvrés ? Une approche consiste à combiner une liste de jours fériés et une logique conditionnelle via CASE WHEN. Par exemple, vous pouvez créer une table de calendrier énumérant chaque date, avec une colonne indiquant si le jour est ouvré ou non.
La requête de calcul d’ancienneté réalisera alors une jointure avec ce calendrier et comptera seulement les jours marqués comme ouvrés : SUM(CASE WHEN jour_ouvre = 1 THEN 1 ELSE 0 END). Cette technique, certes un peu plus complexe à mettre en place, offre une grande souplesse : vous pouvez facilement adapter les règles (semaines de 4 jours, jours fériés locaux, etc.) sans modifier la logique de comparaison de dates en SQL au cœur de vos requêtes métiers.
Requêtes de plages dynamiques avec CURRENT_DATE et INTERVAL
Dans les tableaux de bord et rapports opérationnels, on travaille rarement avec des dates fixes : on veut « les 7 derniers jours », « le mois en cours », « le trimestre précédent ». Pour cela, les fonctions CURRENT_DATE, NOW(), GETDATE() ou SYSDATE associées au mot-clé INTERVAL (selon le SGBD) sont incontournables. Elles permettent de construire des plages temporelles dynamiques sans modifier le code SQL à chaque période.
Un exemple classique sous PostgreSQL : WHERE created_at >= CURRENT_DATE - INTERVAL '30 days' pour les 30 derniers jours. Sous MySQL, on écrira plutôt WHERE created_at >= NOW() - INTERVAL 30 DAY. En adoptant systématiquement ce type de conditions, vous facilitez la maintenance de vos rapports et garantissez que vos comparaisons de dates en SQL reflètent toujours l’état le plus récent des données.
Jointures temporelles et window functions pour analyses chronologiques
Les analyses chronologiques avancées, par exemple comparer chaque valeur à celle du jour précédent ou calculer un délai entre deux événements successifs, s’appuient souvent sur les window functions comme LAG() et LEAD(). Elles permettent d’accéder aux lignes « voisines » dans un ordre temporel donné, sans recourir à des auto-jointures complexes. Par exemple, LAG(event_time) OVER (PARTITION BY user_id ORDER BY event_time) vous donne la date de l’événement précédent pour chaque utilisateur.
Vous pouvez ensuite calculer la différence entre ces timestamps pour mesurer des durées de sessions, des délais de réponse ou des intervalles entre deux visites. Cette combinaison de window functions et de comparaisons de dates en SQL ouvre la voie à une multitude d’analyses, depuis la détection d’anomalies (délai trop court ou trop long) jusqu’au calcul de KPI sophistiqués (temps moyen entre deux achats, fréquence de connexion, etc.).
Détection de chevauchements de périodes avec EXISTS et NOT EXISTS
Dans de nombreux modèles métier (réservations, contrats, abonnements), il est essentiel de détecter les chevauchements de périodes. La question typique : « Cette nouvelle réservation de salle ne chevauche-t-elle pas une réservation existante ? ». La règle générale pour deux intervalles [start1, end1] et [start2, end2] est qu’ils se chevauchent si start1 < end2 AND start2 < end1. Traduite en SQL, cette condition s’exprime aisément dans une sous-requête EXISTS.
Par exemple : WHERE EXISTS (SELECT 1 FROM reservations r2 WHERE r2.room_id = r1.room_id AND r2.start_time < r1.end_time AND r2.end_time > r1.start_time). À l’inverse, pour garantir l’absence de chevauchement, vous utiliserez NOT EXISTS avec la même condition. Cette technique de comparaison de dates en SQL est au cœur de la validation de nombreuses règles métier, et son bon usage évite des incohérences coûteuses dans les systèmes de réservation, de planning ou de gestion de ressources.