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:
-
allCars
userid
ioverLap
userid
musi być taki sam -
allCars
rekord samochodu ioverlap
rekord samochodu musi być inny -
allCars
zakres czasu ioverLap
zakres 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
NOT
do 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
.