Oto pierwsza część:Nakładające się samochody na użytkownika...
SQLFiddle — skorelowane zapytanie i połączenie zapytania
Część druga - więcej niż jeden użytkownik w jednym samochodzie jednocześnie:SQLFiddle - skorelowane zapytanie i dołączanie Zapytanie . Zapytanie poniżej...
Używam skorelowanych zapytań:
Prawdopodobnie będziesz potrzebować indeksów na identyfikator użytkownika i „samochód”. Jednak - sprawdź plan wyjaśnień, aby zobaczyć, w jaki sposób mysql uzyskuje dostęp do danych. I po prostu spróbuj :)
Nakładające się samochody na użytkownika
Zapytanie:
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`;
Wyniki:
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
Dlaczego to działa? lub jak o tym myślę:
Używam skorelowanego zapytania, więc nie mam duplikatów, z którymi mogę sobie poradzić i prawdopodobnie jest to dla mnie najłatwiejsze do zrozumienia. Istnieją inne sposoby wyrażenia zapytania. Każdy ma zalety i wady. Chcę czegoś, co z łatwością zrozumiem.
Wymagania:Dla każdego użytkownika upewnij się, że nie ma dwóch lub więcej samochodów w tym samym czasie.
Tak więc dla każdego rekordu użytkownika (AllCars) sprawdź pełną tabelę (overlapCar), aby sprawdzić, czy możesz znaleźć inny rekord, który nakłada się na czas bieżącego rekordu. Jeśli go znajdziemy, wybierz bieżący rekord, który sprawdzamy (we wszystkich samochodach).
Dlatego nakładanie się czek to:
-
allCarsuseridioverLapuseridmusi być taki sam -
allCarsrekord samochodu ioverlaprekord samochodu musi być inny -
allCarszakres czasu ioverLapzakres czasu musi się pokrywać.Sprawdzenie zakresu czasu:
Zamiast sprawdzać, czy czasy się nakładają, użyj pozytywnych testów. Najłatwiejszym sposobem jest sprawdzenie, czy nie zachodzi na siebie, i zastosowanie
NOTdo niego.
Jeden samochód z więcej niż jednym użytkownikiem w tym samym czasie...
Zapytanie:
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`;
Wyniki:
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
Edytuj:
W związku z komentarzami @philipxy , dotyczącymi zakresów czasowych wymagających sprawdzenia „większego lub równego”, zaktualizowałem tutaj kod. Nie zmieniłem SQLFiddles .