jednoduchy Sql dotaz s joinem

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

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

nejak takhle:

foreach($connection->table('programy')->where('os:type', 'windows') as $program) {

	foreach($program->related('os') as $os) {

	}
}
esorimer
Člen | 114
+
0
-

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)

wb2009
Člen | 125
+
0
-

Všechno jde, ale Nette to catchuje, takže poprvé ti to sice bude chvilku trvat, než se vyrenderuje, ale pak už si to pamatuje a a je to hned, jestli ti jde o rychlost…

Editoval wb2009 (17. 4. 2013 17:31)

esorimer
Člen | 114
+
0
-

wb2009 napsal(a):

Všechno jde, ale Nette to catchuje, takže poprvé ti to sice bude chvilku trvat, než se vyrenderuje, ale pak už si to pamatuje a a je to hned, jestli ti jde o rychlost…

To se mi nějak nezdá. Co přesně se cachuje?

David Matějka
Moderator | 6445
+
0
-

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)

esorimer
Člen | 114
+
0
-

Pokladalo to pořád dotaz navíc, ale ta hvězdička pomohla. Diky.

wb2009
Člen | 125
+
0
-

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

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

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

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

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ý :)