MYSQL - SELECT na podstawie czasu wydarzenia

0

Witajcie!

Chcę skonstruować zapytanie do bazy które zwróci mi dane jeśli nie trwa w tym momencie inne zdarzenie. Ciężko mi to wyjaśnić więc:
mam tabelę z miejscem i tytułem zdarzenia, dniem wydarzenia (DATE), godziną rozpoczęcia wydarzenia (TIME - sama godzina + minuty) i godziną zakończenia wydarzenia (również TIME - godziny i minuty)

Mam problem z stworzeniem zapytania do bazy które zwróciłoby mi z tabeli miejsce w przypadku gdy nic w podanych godzinach się nie dzieje (i miejsce jest wolne "do obsadzenia").
Dajmy na to:
mam restaurację (miejsce) zamkniętą z powodu imprezy (wydarzenie) w dniu 04.09.2015 w godzinach 15 (godzina rozpoczęcia) - 18 (godzina zakończenia) i select miałby mi zwrócić miejsce (restaurację) jeśli to miejsce byłoby wolne, np. przy podaniu 04.09.2015 10-15 lub 10.09.2015 15-18. Jeśli podałbym np. 04.09.2015 16-17 to nic by nie zwrócił.

Męczę się z tym już dłuższy czas i nic mi nie wychodzi...
Z góry dzięki za pomoc!

0

weź wszystkie miejsca i odejmij te, w których coś się dzieje

0
abrakadaber napisał(a):

weź wszystkie miejsca i odejmij te, w których coś się dzieje

Doszedłem do SELECT miejsce FROM wydarzenia WHERE
:P I stoję w miejscu...

EDIT: Czy za pomocą BETWEEN dam radę porównać godziny?

0

nie słuchasz - napisz jedno zapytanie, które zwróci wszystkie miejsca. Zrób drugie zapytanie, które zwróci wszystkie wydarzenia właśnie trwające - jeśli masz datę i godzinę od do to możesz zrobić tak WHERE trunc(data) = trunc(now()) and DATE_FORMAT(NOW(), '%H:%i') between czas_od and czas_do i odejmij je od siebie

1

Termin jest wolny, jeśli zakres wyszukiwany w całości mieści się między końcem jednego wydarzenia a początkiem następnego w danym miejscu.
Poniższe zapytanie powinno być OK:

SELECT DISTINCT
  miejsce
FROM
  wydarzenia W
WHERE
  '2015-09-04 10:00:00' BETWEEN 
    CONCAT(W.data_wydarzenia,' ',W.godzina_wydarzenia_do) 
    AND IFNULL((
      SELECT 
        MIN(CONCAT(data_wydarzenia,' ',godzina_wydarzenia_od)) 
      FROM 
        wydarzenia 
      WHERE 
        miejsce = W.miejsce 
        AND CONCAT(data_wydarzenia,' ',godzina_wydarzenia_od) > CONCAT(W.data_wydarzenia,' ',W.godzina_wydarzenia_do)
     ), '9999-12-31 23:59:59')
  
  AND '2015-09-04 15:00:00' BETWEEN 
    CONCAT(W.data_wydarzenia,' ',W.godzina_wydarzenia_do) 
    AND IFNULL((
      SELECT 
        MIN(CONCAT(data_wydarzenia,' ',godzina_wydarzenia_od)) 
      FROM 
        wydarzenia 
      WHERE 
        miejsce = W.miejsce 
        AND CONCAT(data_wydarzenia,' ',godzina_wydarzenia_od) > CONCAT(W.data_wydarzenia,' ',W.godzina_wydarzenia_do)
      ), '9999-12-31 23:59:59')

Przy okazji proponuję nie przechowywać dat jako dzień i czas od do, a pełne daty (DATETIME) od i do - jeśli założysz indeks na tę kolumnę, to zapytanie tego typu będzie działać znacznie szybciej, poza tym nie zamykasz sobie drogi na to, że wydarzenie może trwać więcej, niż jeden dzień. No i dodatkowo samo zapytanie się trochę uprości :).
W razie potrzeby mogę wyjaśnić powyższe zapytanie, bo na pierwszy rzut oka wygląda na skomplikowane.

[Adam]

0
kchteam napisał(a):

Termin jest wolny, jeśli zakres wyszukiwany w całości mieści się między końcem jednego wydarzenia a początkiem następnego w danym miejscu.
Poniższe zapytanie powinno być OK:

SELECT DISTINCT
  miejsce
FROM
  wydarzenia W
WHERE
  '2015-09-04 10:00:00' BETWEEN 
    CONCAT(W.data_wydarzenia,' ',W.godzina_wydarzenia_do) 
    AND IFNULL((
      SELECT 
        MIN(CONCAT(data_wydarzenia,' ',godzina_wydarzenia_od)) 
      FROM 
        wydarzenia 
      WHERE 
        miejsce = W.miejsce 
        AND CONCAT(data_wydarzenia,' ',godzina_wydarzenia_od) > CONCAT(W.data_wydarzenia,' ',W.godzina_wydarzenia_do)
     ), '9999-12-31 23:59:59')
  
  AND '2015-09-04 15:00:00' BETWEEN 
    CONCAT(W.data_wydarzenia,' ',W.godzina_wydarzenia_do) 
    AND IFNULL((
      SELECT 
        MIN(CONCAT(data_wydarzenia,' ',godzina_wydarzenia_od)) 
      FROM 
        wydarzenia 
      WHERE 
        miejsce = W.miejsce 
        AND CONCAT(data_wydarzenia,' ',godzina_wydarzenia_od) > CONCAT(W.data_wydarzenia,' ',W.godzina_wydarzenia_do)
      ), '9999-12-31 23:59:59')

Przy okazji proponuję nie przechowywać dat jako dzień i czas od do, a pełne daty (DATETIME) od i do - jeśli założysz indeks na tę kolumnę, to zapytanie tego typu będzie działać znacznie szybciej, poza tym nie zamykasz sobie drogi na to, że wydarzenie może trwać więcej, niż jeden dzień. No i dodatkowo samo zapytanie się trochę uprości :).
W razie potrzeby mogę wyjaśnić powyższe zapytanie, bo na pierwszy rzut oka wygląda na skomplikowane.

[Adam]

Wielkie dzięki :)
Zastanawiam się poważnie nad zmianą zakresu od do na typ datetime tak jak piszesz - jak wtedy wyglądałoby to zapytanie?

1

Każde wystąpienie CONCAT(data_wydarzenia,' ',godzina_wydarzenia_od/do) trzeba zamienić na data_wydarzenia_od/data_wydarzenia_do (zakładam, że nowe kolumny właśnie tak się nazywają), czyli:

SELECT DISTINCT
  miejsce
FROM
  wydarzenia W
WHERE
  '2015-09-04 10:00:00' BETWEEN 
    W.data_wydarzenia_do
    AND IFNULL((
      SELECT 
        MIN(data_wydarzenia_od)
      FROM 
        wydarzenia 
      WHERE 
        miejsce = W.miejsce 
        AND data_wydarzenia_od > W.data_wydarzenia_do
     ), '9999-12-31 23:59:59')

  AND '2015-09-04 15:00:00' BETWEEN 
    W.data_wydarzenia_do 
    AND IFNULL((
      SELECT 
        MIN(data_wydarzenia_od) 
      FROM 
        wydarzenia 
      WHERE 
        miejsce = W.miejsce 
        AND data_wydarzenia_od > W.data_wydarzenia_do
      ), '9999-12-31 23:59:59')

[Adam]

0
kchteam napisał(a):

Każde wystąpienie CONCAT(data_wydarzenia,' ',godzina_wydarzenia_od/do) trzeba zamienić na data_wydarzenia_od/data_wydarzenia_do (zakładam, że nowe kolumny właśnie tak się nazywają), czyli:

SELECT DISTINCT
  miejsce
FROM
  wydarzenia W
WHERE
  '2015-09-04 10:00:00' BETWEEN 
    W.data_wydarzenia_do
    AND IFNULL((
      SELECT 
        MIN(data_wydarzenia_od)
      FROM 
        wydarzenia 
      WHERE 
        miejsce = W.miejsce 
        AND data_wydarzenia_od > W.data_wydarzenia_do
     ), '9999-12-31 23:59:59')

  AND '2015-09-04 15:00:00' BETWEEN 
    W.data_wydarzenia_do 
    AND IFNULL((
      SELECT 
        MIN(data_wydarzenia_od) 
      FROM 
        wydarzenia 
      WHERE 
        miejsce = W.miejsce 
        AND data_wydarzenia_od > W.data_wydarzenia_do
      ), '9999-12-31 23:59:59')

[Adam]

A jak będzie wyglądało zapytanie które zwraca zajęte miejsca zamiast wolnych?

1

Miejsce jest zajęte, jeśli wydarzenie zaczyna się lub kończy w wyszukiwanym przedziale czasu lub wyszukiwany zakres w całości trafia w trwające wydarzenie.

SELECT
  miejsce
FROM
  wydarzenia W
WHERE
  W.data_wydarzenia_od BETWEEN '2015-09-10 08:15:00' AND '2015-09-10 08:25:00'

UNION

SELECT
  miejsce
FROM
  wydarzenia W
WHERE
  W.data_wydarzenia_do BETWEEN '2015-09-10 08:15:00' AND '2015-09-10 08:25:00'
  
UNION

SELECT
  miejsce
FROM
  wydarzenia W
WHERE 
  W.data_wydarzenia_od <= '2015-09-10 08:15:00'
  AND W.data_wydarzenia_do >= '2015-09-10 08:25:00'
 AND W.data_wydarzenia_od <= W.data_wydarzenia_do
;

Zapytanie nie ma DISTINCT, ponieważ w tym przypadku jest on zapewniony przez UNION (proponuję UNION, żeby uniknąć warunku OR na teoretycznie indeksowanej kolumnie).

[Adam]

0
kchteam napisał(a):

Miejsce jest zajęte, jeśli wydarzenie zaczyna się lub kończy w wyszukiwanym przedziale czasu.

SELECT
  miejsce
FROM
  wydarzenia W
WHERE
  W.data_wydarzenia_od BETWEEN '2015-09-04 10:00:00' AND '2015-09-04 15:00:00'

UNION

SELECT
  miejsce
FROM
  wydarzenia W
WHERE
  W.data_wydarzenia_do BETWEEN '2015-09-04 10:00:00' AND '2015-09-04 15:00:00'

Zapytanie nie ma DISTINCT, ponieważ w tym przypadku jest on zapewniony przez UNION (proponuję UNION, żeby uniknąć warunku OR na teoretycznie indeksowanej kolumnie).

[Adam]

Super, wielkie dzięki, męczyłem się z tym i nie mogłem dojść do porządku. Niestety jakoś nie wchodzi mi do głowy ten MYSQL...

EDIT: Mam problem z tym zapytaniem :/
Jeśli mam rekord którego data_wydarzenia_od oraz data_wydarzenia_do zawiera się między podaną datą to nie zwraca mi wydarzenia...

Np. w rekordzie jest:
data_wydarzenia_od - 10.09.2015 08:11
data_wydarzenia_do - 10.09.2015 08:26.

I teraz miejsce jest zajęte zarówno:
od godziny 08:00 do 08:15,
od 08:20 do 08:30
i od 08:15 do 08:25.

A wg zapytania jest zajęte tylko
od 08:00 do 08:15
i od 08:20 do 08:30 :/

Pomija całkowicie od 08:15 do 08:25 - czyli przypadek gdy godziny zawierają się obydwie między od/do.

1 użytkowników online, w tym zalogowanych: 0, gości: 1