Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Finden Sie Überschneidungen von Datumsbereichen innerhalb derselben Tabelle für bestimmte MySQL-Benutzer

Hier ist der erste Teil:Überlappende Autos pro Benutzer...

SQLFiddle - korrelierte Abfrage und Join-Abfrage

Zweiter Teil - mehr als ein Benutzer gleichzeitig in einem Auto:SQLFiddle - korrelierte Abfrage und Verknüpfung Abfrage . Abfrage unten...

Ich verwende die korrelierten Abfragen:

Sie benötigen wahrscheinlich Indizes für Benutzer-ID und „Auto“. Bitte überprüfen Sie jedoch den 'Explain Plan', um zu sehen, wie mysql auf die Daten zugreift. Und probiere es einfach aus :)

Überlappende Autos pro Nutzer

Die Abfrage:

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`;      

Die Ergebnisse:

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

Warum es funktioniert? oder wie ich darüber denke:

Ich verwende die korrelierte Abfrage, damit ich nicht mit Duplikaten umgehen muss, und sie ist wahrscheinlich am einfachsten für mich zu verstehen. Es gibt andere Möglichkeiten, die Abfrage auszudrücken. Jeder hat Vor- und Nachteile. Ich möchte etwas, das ich leicht verstehen kann.

Anforderung:Stellen Sie für jeden Benutzer sicher, dass er nicht zwei oder mehr Autos gleichzeitig hat.

Überprüfen Sie also für jeden Benutzerdatensatz (AllCars) die vollständige Tabelle (overlapCar), um zu sehen, ob Sie einen anderen finden können Aufzeichnung, die sich mit der Zeit der aktuellen Aufzeichnung überschneidet. Wenn wir einen finden, wählen Sie den aktuellen Datensatz aus, den wir prüfen (in allCars).

Daher die Überschneidung Prüfung ist:

  • die allCars userid und der overLap userid muss gleich sein

  • die allCars Fahrzeugrekord und die overlap Autodatensatz muss unterschiedlich sein

  • die allCars Zeitbereich und der overLap Zeitbereich muss sich überschneiden.

    Zeitbereichsprüfung:

    Anstatt nach sich überschneidenden Zeiten zu suchen, verwenden Sie positive Tests. Der einfachste Ansatz besteht darin, zu überprüfen, ob es sich nicht überschneidet, und ein NOT anzuwenden dazu.

Ein Auto mit mehr als einem Benutzer gleichzeitig...

Die Abfrage:

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`;

 

Die Ergebnisse:

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

Bearbeiten:

In Anbetracht der Kommentare von @philipxy über Zeitbereiche, die Prüfungen auf „größer als oder gleich“ erfordern, habe ich den Code hier aktualisiert. Ich habe die SQLFiddles nicht geändert .