Spojování tabulek a vytváření objektu Table\Selection z jednotlivých řádků
- mere.gee
- Člen | 54
Zdravím! Přicházím se snad trochu netradičním problémem :)
Mám následující tabulky z helpdeskové databáze: ticket, customer,
agent a ty jsou spojené pomocí FK k tabulce note. Potřeboval bych:
projít všechny tickety->pro každý najít časově poslední
note->přečíst z note (subject, state, priority, customerid, agentid),
podle customerid, agentid zjistit jména z customer, agent, něco
spočítat->z těchto dat vytvořit řádek->z těchto informací
vytvořit „řádek“ objektu Nette\Database\Table\Selection, abych výsledek
mohl spojit s doplňkem Grido. Lze to vůbec udělat?
Díky moc
- JHadamcik
- Člen | 47
Kdybych to měl zapsat v SQL tak bych napsal něco jako:
SELECT c.customer, a.agent, n.subjectpriority, n.state, n.priority, n.customerid, n.agentid FROM (note n LEFT JOIN customer c ON(n.customerid = c.id)) LEFT JOIN agent a ON (n.agentid = a.id) WHERE n.id IN (SELECT noteid FROM ticket ORDER BY datetime DESC LIMIT 1);
Správně to chápu?
Jestli ano pak prostě převést tenhle dotaz do Nette a ve výsledku ti to vrátí řádky, které chceš s informacemi, které potřebuješ a to už si projdeš.
- mere.gee
- Člen | 54
Omlouvám se, ono to je trochu složitější, než jsem popsal. customer není spojen s note, jak jsi předpokládal, ale s ticket pomocí tabulky ticket_to_customer, takže takhle jednoduše to nepůjde. Navíc potřebuji kód nezávislý na databázi, protože nejspíš se to bude nasazovat na postgresu.
- JHadamcik
- Člen | 47
Ta propojovací tabulka není problém SQL by se jen trochu upravilo.
No nevím jak chceš řešit tu logiku v aplikaci, ale myslel jsem, že tady je největší problém to co jsem se snažil vyřešit. I kdyby jsi to pak naparsoval na více dotazů a nedělal jeden složitý tak by se ti měl povést udělat kód nezávislý na databázi, ne?
Doufám, že to nechápu pořád špatně a alespoň k něčemu ti to je.
- mere.gee
- Člen | 54
Díky za snahu, jsem vděčný za každou radu :)
Ty problému zřejmě rozumíš perfektně, spíš já nerozumím tobě. Jak bych měl vytvořit kód nezávislý na DBMS? Já myslel, že PostgreSQL má jinou syntax, než MySQL. A tak bych to rád vyřešil přes aplikační logiku v Nette, aby to bylo maximálně přenosné a snažím se zjistit, jestli to jde…
- JHadamcik
- Člen | 47
Neřeší tohle model? Zavoláš funkci modelu a je ti jedno co dělá, důležité je co ji posíláš a co ti vrací.
Čili: Je fuk, jestli model dělá s Postgresem, Mysql nebo něčím dalším. No a pokud chápu dobře tvou „maximální přenositelnost“ pak pokud ti jde o to, že nevíš jestli tam bude nebo nebude Postgres, udělej to tak, že si třeba zavoláš funkci modelu getLastNotes() a tu si napiš pro Postgres. Když budeš chtít použít něco jiného než postgres tak přepíšeš getLastNotes() jinou logikou, ale tak aby přijímala a vracela pořád to stejné.
Mimo model pak zpracuješ to co ti vrátila a pak si zavoláš třeba metodu v modelu getNoteInfo($noteId) a jedeš pořád dál a dál. To je to co jsem říkal – rozkouskovat si to, pokud nejsi schopen to udělat v jednom velkém dotazu třeba nad postgresem.
IMHO problému nerozumím vůbec, ale snažím se alespoň nějak poradit a třeba to vyřešit i já se tím učím.
- mere.gee
- Člen | 54
Máš pravdu, že nečistší to asi bude udělat jednou metodou s velkým dotazem v modelu. Takhle jsem si to představoval, akorát bez toho dotazu…
Mohl bys mi, prosím, poradit, jak by ten dotaz vypadal v MySQL, když ta databáze vypadá takhle? http://i40.tinypic.com/2hghbo0.png
Editoval mere.gee (13. 7. 2013 23:04)
- JHadamcik
- Člen | 47
SELECT t.idticket, a.agent_name, n.note_subject, n.note_state, n.note_priority FROM (ticket t LEFT JOIN note n USING (idticket)) LEFT JOIN agent a ON (a.idagent = n.idagent) WHERE n.idnote = (SELECT idnote FROM note WHERE idticket=t.idticket ORDER BY note_worktime DESC LIMIT 1);
Je pozdě a SQL už jsem nějakou dobu nedělal takže tohle fungovat prostě nebude já se znám. Každopádně nějaký popis jak jsem to myslel a jak si myslím, že by to nějak mohlo uvažovat:
- Zvolím si sloupečky o které mám zájem: idticket, agent_name, note_subject, note_state, note_priority
- Pak si propojím tabulky
- Dodám podmínku, že chci to idnote, které odpovídá poslednímu záznamu pro daný idticket.
Fakt si nejsem jist, ale agent_name by se mělo pořešit přes propojení tabulek note a agent a jak si říkal, že chceš customer name tak to se mi nějak nezdá, pokud tam máš propojení M:N tak ti nikdo nezaručí, že ti to hodí jen jeden záznam ne?
Edit: Zákazníky, kteří mají co dělat s tím ticketem bych si zjišťoval v dalším dotazu, který se zavolá s idticket parametrem získaným z tohoto prvního dotazu a jeho obsah by byl
SELECT c.customer_name FROM customer c LEFT JOIN ticket_to_customer ttc USING (idcustomer) WHERE ttc.idticket = <idticket_parametr>;
Editoval JHadamcik (13. 7. 2013 23:56)
- JHadamcik
- Člen | 47
V tom případě dej do tabulky ticket idcustomer a prostě přidej customer_name do výběru v tom 1. dotazu a dodej LEFT JOIN customer c ON (t.idcustomer = c.idcustomer)
To už zvládneš nějak. Nejlepší budeš mít, když si ten dotaz dáš třeba do PhpMyAdmin a uvidíš co dělá. Doufám, že bude chtít jen pár úprav.
- JHadamcik
- Člen | 47
Jak říkám – nečekám, že to bude fungovat napoprvé. Každopádně můžeš zkusit ten dotaz změnit na:
SELECT t.idticket, a.agent_name, c.customer_name n.note_subject, n.note_state, n.note_priority FROM (((ticket t LEFT JOIN note n USING (idticket)) LEFT JOIN agent a ON (a.idagent = n.idagent)) LEFT JOIN ticket_to_customer ttc ON (ttc.idticket = t.idticket)) LEFT JOIN customer c ON (c.idcustomer = ttc.idcustomer) WHERE n.idnote = (SELECT idnote FROM note WHERE idticket=t.idticket ORDER BY note_worktime DESC LIMIT 1);
Nevím jak to vrátí při tomhle propojení, každopádně umožňuje to možnost pro chybu, že se vrátí víc než jeden řádek při tom propojení M:N (pokud to teda vůbec mysql pochroustá).