Spojování tabulek a vytváření objektu Table\Se­lection z jednotlivých řádků

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
mere.gee
Člen | 54
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

Uvažuji je to trochu hardcore, dej mi chvíli snažím se to udělat nějak hezky a hlavně funkčně. Píšu z hlavy tak bychom to pak doladili, kdybych se sekl v úvaze.

JHadamcik
Člen | 47
+
0
-

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)

mere.gee
Člen | 54
+
0
-

Každému ticketu je přiřazen jeden zákazník, takže prakticky to propojení je 1:N…

JHadamcik
Člen | 47
+
0
-

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.

mere.gee
Člen | 54
+
0
-

No, nevím, jestli můžu měnit strukturu databáze… Zítra se optám a otestuji… Díky moc! Jestli to bude fungovat, tak tě zvu na pivo ;)

JHadamcik
Člen | 47
+
0
-

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á).