Autor Zpráva
jakubk0c
Profil
Donrý den všem,
narazil jsem na problém a chtěl bych se s váma poradit jak to správně řešit.
Jedná se o rezervační systém denní, s kapacitou na den = 600mist.
uživatel si zadá datum příjezdu (6.11.2018) a dojezdu (14.11.2018) jméno, příjmení atd.

Do datábaze do jednou sloupce bych přidával (db_datum_příjezdu a do druhého db_datum_odjezdu, id, jméno atd.)

Situace v DB (berte, že je v DB 600 stejných záznamů)
id | jmeno | db_datum_příjezdu | db_datum_odjezdu
1 | Petr | 8.11 | 13.11
600 | Lukáš | 9.11 | 14.11

uživatel do formuláře vyplní ...jmeno xx, datum prijzedu 6.11.2018 7:00 a datum odjezdu 14.11.2018

A potřebuji jak otestovat, zda je v tom termínu již zabráno 600 míst.
6.11 ok
7.11 ok
8.11 ok
9.11 chyba - již bylo zabráno 600 míst.

budu rád, za každý řešení jak to udělat. ideální by bylo tam dát i hodi
TomášK.
Profil *
1) Najdi všechny záznamy, jejichž interval má neprázdný průnik s novým záznamem.
2) Vygeneruj seznam dvojic, kde pro každý záznam z 1) budou dvě položky: (daum_prijezdu, 1) a (daum_odjezdu, -1).
3) Seřaď seznam 2) podle datumů
4) Proměnnou zabráno nastav na 0, reprezentuje počet zabraných míst; Procházej seznam a do proměnné zabráno přičítej druhou část dvojice (+1/-1). Pokud je datum mezi daty nového internvalu, ověř, že je počet menší než 600.
jakubk0c
Profil
A ten bod 1 jak přesně tu podmínku postavit.
Pomuzes mi se sql příkazem? Prosím
Kajman
Profil
Body 1 až 3 lze jednoduše udělat v databázi. Přibližně takto
SELECT den,
       Sum(zmena) zmena
FROM   (SELECT Greatest(`prijezd`, Str_to_date('2018-11-06 07:00','%Y-%m-%d %H:%i:%s')) den,
               1                                                                        zmena
        FROM   `tabulka`
        WHERE  `odjezd` > Str_to_date('2018-11-06 07:00','%Y-%m-%d %H:%i:%s')
               AND `prijezd` < Str_to_date('2018-11-14 12:00','%Y-%m-%d %H:%i:%s')
        UNION ALL
        SELECT `odjezd` den,
               -1       zmena
        FROM   `tabulka`
        WHERE  `odjezd` > Str_to_date('2018-11-06 07:00','%Y-%m-%d %H:%i:%s')
               AND `odjezd` < Str_to_date('2018-11-14 12:00','%Y-%m-%d %H:%i:%s')) d
GROUP  BY den
ORDER  BY den

Pokud nemáte starou mysql, ale něco, co umí window funkce, tak tam jde jednoduše i ten 4. bod.

A pokud bude v tabulce možné rezervovat více míst jednou objednávkou, tak místo 1 a -1 dáte ten počet míst a jeho zápornou hodnotu.

Edit:
Date zaměněno na Str_to_date (aby fungovaly i minuty)
na řádku 13 změněn prijezd za odjezd (odjezdy po termínu není potřeba sčítat)
TomášK
Profil
Pokud máš nějakou lepší databázi, tak
SELECT * FROM t WHERE (db_datum_příjezdu , db_datum_odjezdu) OVERLAPS ($1, $2)

Pokud máš MySQL, tak si rozepiš ty 4 případy, které můžou nastat (nový záznam je podinterval, nadinterval, překrývá se částečně zleva / zprava) a vyber si ty, kde se intervaly překrývají. Nebo naopak vyhoď ty, které se nepřekrývají, to je jen 1 z těch 4 případů, bude to kratší.
jakubk0c
Profil
Je to InnoDb. Napsal bys řešení i s tím bodem 4? Prosím
Kajman
Profil
select version()
?
jakubk0c
Profil
Hosting teprv budu kupovat. Tak se podřídím. Jakou verzi potřebuji? Klidně i doporučení kde.
Davex
Profil
jakubk0c:
Jakou verzi potřebuji?
mariadb.com/kb/en/library/window-functions
Kajman
Profil
Sčítání všech dosavadních změn a vypsání případných problémových dnů, kdy byl překročen limit (600 míst a jedno chci = 599) by mohlo být něco jako
SELECT *
FROM   (SELECT t.den,
               Lead(den)  OVER(ORDER BY den) az,
               Sum(zmena) OVER(ORDER BY den) obsazeno
        FROM   (SELECT '...dotaz z [#4]... bez order by') t
       ) x
WHERE  x.obsazeno > 599 

Edit: přidán sloupec az pro lepší výpis termínů s přílišnou obsazeností
jakubk0c
Profil
jakubk0c, Kajman:
Zeptám se tady musím mít teda tu "mariadb.com/kb/en/library/window-functions" aby to fungovalo?
Ptám se proto, že mi to píše: "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(ORDER BY den) obsazeno FROM (SELECT 'SELECT den, Sum(zmena) zm' at line 3";

Jinak ten dotaz z [#4] funguje super. Todle prohledává, všechny záznamy, nešlo by to nějak vyfiltrovat, aby to neprohledávalo třeba 1 000 000 záznamů, ale jen 1000 např. Dát tomu nějaké omezení.
Kajman
Profil
Na té stránce je napsaná verze mariadb (je kompatibilní s mysql), od které v ní window funkce fungují. I mysql už tu podporu má od verze 8.0. Je pak spousta databází, které to podporují také, ale kromě postresql asi nebudou na hostinzích tak často podporované, jako mariadb.

Je potřeba najít jen záznamy v hledaném intervalu díky where. Zrychlit toto omezení je možné vytvořením indexů na těch sloupcích s příjezdem a odjezdem. Pokud je v intervalu milion záznamů, tak se musí sečíst všechny.

Nyní tam jsou dvě vyhledávání spojené unionem. Ještě je možné udělat jedno vyhledávání a rozdvojit ho cross joinem na přičítací a odčítací řádky. To si můžete zkusit za domácí úkol a porovnat výsledky, zda je nějaké řešení rychlejší.
jakubk0c
Profil
Kajman:
Když to testuji a zadám interval 16-22.12.2018

V DB mám záznamy 2018-12-20 00:00:00 2018-12-25 00:00:00
A adminer vyhodí:
den změna
2018-12-20 00:00:00 | 8
2018-12-22 00:00:00 | -8

Ale nikde se netestuje, zda je volno i 21.12.2018
2018-12-21 00:00:00

Jak toho docílím? Díky moc za pomoc.

Odkaz_adminer
Kajman
Profil
Pokud 21.12. nikdo nepřijel ani neodjel, tak tam bude stejný počet lidí, jako toho 20.12.
jakubk0c
Profil
Kajman:
V DB budu mít 598x záznam: 2018-12-20 00:00:00 | 2018-12-25 00:00:00
A přidají se tam rezervace 3 x 2018-12-21 00:00:00 | 2018-12-25 00:00:00

Tak obsazenost 2018-12-20 = 598
2018-12-21 = 601
2018-12-22 = 598

Ale ten script udělá 2018-12-20 = 598
2018-12-21 = 3
2018-12-22 = -598

A nehodí mi 601.
Kajman
Profil
Moc nechápu, kde máte problém. Pokud nemáte podporu window funkcí, tak v php musíte ty změny sčítat. To je ten krok 4.

A pokud chcete rezervovat 3 místa, tak musíte kontrolovat, že ten průměžný součet v php nikdy není víc než 597 (600-3).
jakubk0c
Profil
Kajman:
Už to chápu, moc Vám děkuju :-).
jakubk0c
Profil
Ještě jsem narazil na 1 problém.

...den,
               1  zmena
        FROM...
`odjezd` den,
              -1  zmena
 

id | jmeno | db_datum_příjezdu | db_datum_odjezdu | pocet
1 | Petr | 8.11 | 13.11 | 5

Potřeboval bych tu : 1 ; -1

nahradit proměnou `pocet` co má v DB. Výsledek
5 ; -5
Kajman
Profil
Stačilo číst pořádně... viz [#4]
A pokud bude v tabulce možné rezervovat více míst jednou objednávkou, tak místo 1 a -1 dáte ten počet míst a jeho zápornou hodnotu.

... den,
`pocet` zmena
... 
... den,
-`pocet` zmena
...
jakubk0c
Profil
Dík, já to zkoušel a nešlo mi to, ale měl jsem chybu jinde. Teď to šlape, mockrát vám děkuji.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0