Mysql
 sql >> Base de données >  >> RDS >> Mysql

Trouver des chevauchements de plages de dates dans la même table, pour un utilisateur MySQL spécifique

Voici la première partie :Chevauchement de voitures par utilisateur...

SQLFiddle - requête corrélée et requête de jointure

Deuxième partie - plus d'un utilisateur dans une voiture en même temps :SQLFiddle - requête et jointure corrélées Requête . Requête ci-dessous...

J'utilise les requêtes corrélées :

Vous aurez probablement besoin d'index sur userid et 'car'. Cependant - veuillez vérifier le "plan d'explication" pour voir comment mysql accède aux données. Et essayez-le :)

Voitures qui se chevauchent par utilisateur

La requête :

SELECT `allCars`.`userid`  AS `allCars_userid`, 
       `allCars`.`car`     AS `allCars_car`, 
       `allCars`.`From`    AS `allCars_From`, 
       `allCars`.`To`      AS `allCars_To`,
       `allCars`.`tableid` AS `allCars_id`
 FROM  
       `cars` AS `allCars`
 WHERE 
     EXISTS  
         (SELECT 1       
          FROM `cars` AS `overlapCar`            
          WHERE 
               `allCars`.`userid` = `overlapCar`.`userid` 
           AND `allCars`.`tableid` <> `overlapCar`.`tableid`          
           AND NOT (   `allCars`.`From`  >= `overlapCar`.`To`      /* starts after outer ends  */  
                    OR `allCars`.`To`    <= `overlapCar`.`From`))  /* ends before outer starts */
 ORDER BY
        `allCars`.`userid`, 
        `allCars`.`From`, 
        `allCars`.`car`;      

Les résultats :

allCars_userid  allCars_car  allCars_From  allCars_To  allCars_id  
--------------  -----------  ------------  ----------  ------------
             1  Navara       2015-03-01    2015-03-31             3
             1  GTR          2015-03-28    2015-04-30             4
             1  Skyline      2015-04-29    2015-05-31             9
             2  Aygo         2015-03-01    2015-03-31             7
             2  206          2015-03-29    2015-04-30             8
             2  Skyline      2015-04-29    2015-05-31            10

Pourquoi ça marche ? ou Comment j'y pense :

J'utilise la requête corrélée pour ne pas avoir de doublons à gérer et c'est probablement la plus facile à comprendre pour moi. Il existe d'autres façons d'exprimer la requête. Chacun a des avantages et des inconvénients. Je veux quelque chose que je peux facilement comprendre.

Exigence :pour chaque utilisateur, assurez-vous qu'il n'a pas deux voitures ou plus en même temps.

Ainsi, pour chaque enregistrement d'utilisateur (AllCars) vérifiez le tableau complet (overlapCar) pour voir si vous pouvez trouver un différent enregistrement qui se chevauche pour le temps de l'enregistrement en cours. Si nous en trouvons un, sélectionnez l'enregistrement actuel que nous vérifions (dans allCars).

Par conséquent, le chevauchement le chèque est :

  • le allCars userid et le overLap userid doit être le même

  • le allCars dossier de voiture et le overlap l'enregistrement de la voiture doit être différent

  • le allCars plage de temps et le overLap la plage de temps doit se chevaucher.

    La vérification de la plage horaire :

    Au lieu de vérifier les temps qui se chevauchent, utilisez des tests positifs. L'approche la plus simple consiste à vérifier qu'il ne se chevauche pas et à appliquer un NOT à elle.

Une voiture avec plusieurs utilisateurs en même temps...

La requête :

SELECT  `allCars`.`car`     AS `allCars_car`,
        `allCars`.`userid`  AS `allCars_userid`,  
        `allCars`.`From`    AS `allCars_From`, 
        `allCars`.`To`      AS `allCars_To`, 
        `allCars`.`tableid` AS `allCars_id`
        
 FROM  
       `cars` AS `allCars`
 WHERE 
     EXISTS  
        (SELECT 1       
         FROM `cars` AS `overlapUser`            
         WHERE 
              `allCars`.`car` = `overlapUser`.`car` 
          AND `allCars`.`tableid` <> `overlapUser`.`tableid`          
          AND NOT (    `allCars`.`From`  >= `overlapUser`.`To`       /* starts after outer ends  */  
                   OR  `allCars`.`To`    <= `overlapUser`.`From`))  /* ends before outer starts */
 ORDER BY
        `allCars`.`car`,      
        `allCars`.`userid`, 
        `allCars`.`From`;

 

Les résultats :

allCars_car  allCars_userid  allCars_From  allCars_To    allCars_id  
-----------  --------------  ------------  ----------  ------------
Skyline                   1  2015-04-29    2015-05-31             9
Skyline                   2  2015-04-29    2015-05-31            10

Modifier :

Compte tenu des commentaires de @philipxy sur les plages de temps nécessitant des vérifications "supérieur ou égal à", j'ai mis à jour le code ici. Je n'ai pas changé le SQLFiddles .