jednoduchy Sql dotaz s joinem
- esorimer
- Člen | 114
Zdravím,
trochu se teď peru s databází a mám následující problém, který bych
chtěl vyřešit pomocí Nette\Database\Connection:
Mám tabulku s programy. Každý program může pracovat ve více OS (např windows i linux), takže k nim mám ještě tabulku os s cizým klíčem programy_id.
Chci vybrat všechny programy, které jsou pro OS windows a k nim i všechny OS, pro které jsou. Dá se to řešit například těmito 2 SQL dotazy:
SELECT DISTINCT programy.* FROM programy LEFT JOIN os ON programy.id =
os.programy_id WHERE os.type = ‚windows‘ order by … limit …;
SELECT * FROM os WHERE programy_id IN (… nactena id z tabulky
programy …);
Zatím to dělám jen přes příkazy query, ale říkám si že by to šlo lépe …
- David Matějka
- Moderator | 6445
nejak takhle:
foreach($connection->table('programy')->where('os:type', 'windows') as $program) {
foreach($program->related('os') as $os) {
}
}
- esorimer
- Člen | 114
matej21 napsal(a):
nejak takhle:
foreach($connection->table('programy')->where('os:type', 'windows') as $program) { foreach($program->related('os') as $os) { $os[] = new OS($r->toArray()); } }
Tak to funguje, dik :-) Ale potreboval bych jeste drobnost: Ten kod nahore vola 3 SQL dotazy, ikdyz by stacili jen dva. Prvni dotaz se vola na radce s prvnim foreach, druhy dotaz na radce s druhym foreach a treti dotaz na radce s toArray():
SELECT [programy].*
FROM [programy]
INNER JOIN [os] ON [programy].[id] = [os].[programy_id]
WHERE ([os].[type] = ?)
ORDER BY [id]
LIMIT 5
OFFSET 0
SELECT [id], [programy_id]
FROM [os]
WHERE ([os].[programy_id] IN (2, 4, 5, 6, 7))
SELECT *
FROM [os]
WHERE ([os].[programy_id] IN (2, 4, 5, 6, 7))
Da se to nejak zoptimalizovat?
Editoval esorimer (17. 4. 2013 16:41)
- David Matějka
- Moderator | 6445
deje se to i pri refreshy stranky? nette\database by melo zjistit, ze byly potreba vsechny sloupecky a pri refreshy nacist vsechny. jestli porad poklada o dotaz vic, muzes uvest
foreach($program->related('os')->select('*') as $os)
a explicitne tak rict, aby vybiral vsechny sloupecky hned.
a je otazka, jestli opravdu potrebujes to
new OS($os->toArray())
.. pokud ta trida OS ma plnit roli nejake
entity, zkus kouknout po nejake nadstavbe nad nette\database, treba YetORM https://forum.nette.org/…tte-database
Editoval matej21 (17. 4. 2013 18:15)
- wb2009
- Člen | 125
já osobně bych si to na začátku vysypal do arraye někde mimo a ten array pak vyprazdňoval v tom foreachi, aby se nedělal pokaždé znova sql dotaz, ale jak sem psal, nette dtb, jak psal matej21 by to mělo catchovat, catchuje mi to i u dibi, kterou používám já a jsem maximálně spokojen…
v debug baru vidíš rychlost načtení stránky v ms, poprvý by to mělo být déle, pak by to mělo být rychlejší protože Nette dtb porovná dotazy, pokud sedí, vyhodí to z catche…alespoň tak nějak by to laicky řečeno mělo fungovat :D
- esorimer
- Člen | 114
wb2009 napsal(a):
já osobně bych si to na začátku vysypal do arraye někde mimo a ten array pak vyprazdňoval v tom foreachi, aby se nedělal pokaždé znova sql dotaz, ale jak sem psal, nette dtb, jak psal matej21 by to mělo catchovat, catchuje mi to i u dibi, kterou používám já a jsem maximálně spokojen…
v debug baru vidíš rychlost načtení stránky v ms, poprvý by to mělo být déle, pak by to mělo být rychlejší protože Nette dtb porovná dotazy, pokud sedí, vyhodí to z catche…alespoň tak nějak by to laicky řečeno mělo fungovat :D
Ted nevim, jak to myslis s tim array, ale ted s tou hvezdickou to udela jen 2 SQL dotazy, ikdyz to najde treba 5 programu. Lepsi to uz asi nebude :)
- David Matějka
- Moderator | 6445
@esorimer: co pouzivas za verzi nette? ted jsem
zkousel na vyvojove verzi a pri ->toArray()
by to nemelo
pokladat dotaz navic. takze kdyz aktualizujes nette, mozna ani nebudes muset
psat to ->select('*')
:)
Editoval matej21 (17. 4. 2013 20:19)
- wb2009
- Člen | 125
to: matej21: je fakt, že poprvé co vykoná ten dotaz, tak pak se vždy ověřuje jestli se dotaz změnil, nebo ne, pokud ne, tak sáhne do catche, takže by to mělo opravdu vykonat jen 1 dotaz
to esorimer:
takže pokud máš aktuální verzi nette, tak máš o starosti míň :)
jiné řešení:
jinak bych ten dotaz provedl dotaz mimo foreach(aby to ten foreach pokaždé co
vypisuje řádek nevykonával ten dotaz)
a hodnoty z toho dotazu bych si vysypal do arraye a v tom foreachi bych vždy
vypisoval hodnoty z toho naplněného arraye.
existuje spousta knihoven co ti pomáhají s dotazy a s výsledky(Nette má nette database, já například používam dibi, ale je toho mnoho dalšího…)
Editoval wb2009 (17. 4. 2013 20:50)
- esorimer
- Člen | 114
matej21 napsal(a):
@esorimer: co pouzivas za verzi nette? ted jsem zkousel na vyvojove verzi a pri
->toArray()
by to nemelo pokladat dotaz navic. takze kdyz aktualizujes nette, mozna ani nebudes muset psat to->select('*')
:)
Používám 2.0.10 a bez ->select('*')
to dělá ty
3 dotazy, co jsem vypisoval víše. Ale se ->select('*')
jsem
úplně spokojený :)