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 * |
#2 · Zasláno: 18. 12. 2018, 19:45:13
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 |
#3 · Zasláno: 18. 12. 2018, 20:28:00
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 |
#5 · Zasláno: 18. 12. 2018, 20:49:05
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 |
#6 · Zasláno: 18. 12. 2018, 21:06:52
Je to InnoDb. Napsal bys řešení i s tím bodem 4? Prosím
|
||
Kajman Profil |
#7 · Zasláno: 18. 12. 2018, 21:32:04
select version() |
||
jakubk0c Profil |
#8 · Zasláno: 18. 12. 2018, 21:33:29
Hosting teprv budu kupovat. Tak se podřídím. Jakou verzi potřebuji? Klidně i doporučení kde.
|
||
Davex Profil |
#9 · Zasláno: 18. 12. 2018, 21:59:52
|
||
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 |
#12 · Zasláno: 19. 12. 2018, 09:07:08
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 |
#13 · Zasláno: 19. 12. 2018, 09:40:41
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 |
#14 · Zasláno: 19. 12. 2018, 09:55:06
Pokud 21.12. nikdo nepřijel ani neodjel, tak tam bude stejný počet lidí, jako toho 20.12.
|
||
jakubk0c Profil |
#15 · Zasláno: 19. 12. 2018, 10:20:30
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 |
#16 · Zasláno: 19. 12. 2018, 10:38:25
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 |
#17 · Zasláno: 19. 12. 2018, 10:45:45
Kajman:
Už to chápu, moc Vám děkuju :-). |
||
jakubk0c Profil |
#18 · Zasláno: 21. 12. 2018, 10:31:11
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 |
#19 · Zasláno: 21. 12. 2018, 14:18:19
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 |
#20 · Zasláno: 22. 12. 2018, 18:08:25
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.
|
||
Časová prodleva: 5 let
|
0