Autor Zpráva
Kcko
Profil
Ahoj,

mám následující kód na zobrazení tabulky tipéru (tipují na sportovní zápasy)
Jediné co mě zajímá, zda-li by dotaz nešel zoptimalizovat, resp. jestli zvýrazněné části (v LEFT JOINU, které se připojují jako "tabulka") jsou správně, nejsem si jist zda-li jsem to spojil správně a jestli nevybírám větší část dat než je potřeba.

Zkoušel jsem psát podmínku přímo pro konkrétního uživatele ale psalo mi to, že to nezná sloupeček.
Něco ve smyslu

WHERE soutez_id = %i AND user_id = t2.id

Tak jsem to pak spojil tak jak to je nyní a je to funkční, vcelku rychlé (moc jsem to netestoval, je tam málo dat), ale stejně se mi to nepozdává. Díky

public function getTabulka($soutezId)
        {
           return $rows = dibi::fetchAll("

                                
                                SELECT

                                t2.displayName,
                                t2.id user_id,
                                SUM(t3.status = 1 AND t3.vyherni = 1) tiketyVyherni,
                                SUM(t3.status = 1) tiketyUkoncene,
                                SUM(t3.status = 0) tiketyOtevrene,
                                (10000 - IFNULL(tmp2.total, 0) + IFNULL(tmp3.total, 0)) kredit

                                FROM users t2 


                                JOIN (

                                SELECT DISTINCT t1.user_id

                                FROM tip_users_tikety t1
                                JOIN users t2 ON t2.id = t1.user_id
                                WHERE t1.soutez_id = %i
                                ) tmp1 ON t2.id = tmp1.user_id

                                JOIN tip_users_tikety t3 ON t3.user_id = t2.id


                                LEFT JOIN (

                                    SELECT SUM(vsazeno) total, user_id
                                    FROM tip_users_tikety 
                                    WHERE soutez_id = %i
                                    GROUP BY user_id
                                ) tmp2 ON tmp2.user_id = t2.id
                                

                                LEFT JOIN (

                                    SELECT SUM(vyhra) total, user_id
                                    FROM tip_users_tikety 
                                    WHERE soutez_id = %i AND vyherni = 1
                                    GROUP BY user_id
                                ) tmp3 ON tmp3.user_id = t2.id

                                WHERE t3.soutez_id = %i 
                                GROUP BY t2.id     


                                ", 
                                $soutezId,
                                $soutezId,
                                $soutezId,
                                $soutezId
                                
                                 );

        }



Edit: ješte jsem přemýšlel nad korelovaným dotazem, ale to se mi zdá, že by bylo mnohem pomalejší ...

Tj.

místo

LEFT JOIN (
 
                                    SELECT SUM(vyhra) total, user_id
                                    FROM tip_users_tikety 
                                    WHERE soutez_id = %i AND vyherni = 1
                                    GROUP BY user_id
                                ) tmp3 ON tmp3.user_id = t2.id

něco jako
(SELECT SUM(vyhra) total
                                    FROM tip_users_tikety 
                                    WHERE soutez_id = %i AND user_id = t2.id AND vyherni = 1 ) as total
Tori
Profil
Jen se chci zeptat (snažím se pochopit ten dotaz a tomuhle nerozumím): K čemu je tabulka tmp1 - omezení řádků v t2 pouze na tipující? Připadá mi totiž, že ve výsledku dělá totéž jako
JOIN tip_users_tikety t3 ON t3.user_id = t2.id 
WHERE t3.soutez_id = %i 
GROUP BY t2.id
, ale dost možná se pletu. Dostaneš odlišný (=špatný) výsledek, pokud řádky 18-25 vypustíš?

edit: #4: samozřejmě, doufám nezapomenu. :)
Kajman
Profil
Pokud bude třeba 20000 uživatelů, ale např. díky limitu se bude vypisovat jen 20 (a nebude se řadit podle některého ze součtů) měl by být korelovaný poddotaz svižnější. Jinak bude asi rychlejší počítání všeho najednou.

A souhlasím s Tori, těch joinů tam nemusí být tolik.
Kcko
Profil
Tori:
Nepleteš se Tori, je to tam duplicitně, když jsem ten dotaz skládal, tak jsem si toho všiml až na konci, ten JOIN je zbytečný v tom prvním dotazu stačí mít pouze Idčka uživatelů a až pak je spojit s tabulkou users kvůli jejich přezdívce :) jsi bystrá.

Nicméně, tohle není hlavní dotaz, ale díky za zájem.

PS. Můžeme si tykat ne?


Kajman:
Ok, díky za info. Jinak principiálně to spojení je v pořádku, nevím čím to je, možná únavou, ale pořád žiju v domnění, že jsem ten označený kus připojit špatně nebo zbytečně (myslím v těch LEFT JOINech), nějak jsem utvrzen v tom, že bych to tam měl spojit s Id uživatelem ... nebo je to takhle v pořádku?
Tori
Profil
Kajman:
A pomohlo by seskupit první dvě tabulky? (= jestli by se pak tmp2 a tmp3 připojily jen k těm vybraným řádkům z t2. Nevím jestli to optimizér umí sám udělat i v tom původním dotazu, nebo se mu to musí říct.)
FROM (users t2 
JOIN tip_users_tikety t3 ON t3.user_id = t2.id AND t3.soutez_id = %i)

LEFT JOIN ( ... ) tmp2 -- atd.
Kcko
Profil
Nechme to být :). Mám tu ještě jeden oříšek.

SELECT 
r.prijmeni, 
r.jmeno, 
COUNT(zk.udalost) AS zlute, 
COUNT(ck.udalost) AS cervene, 
COUNT(r.id_rozhodci) AS pocet, 
r.id_rozhodci

FROM utkani u
JOIN rozhodci r ON r.id_rozhodci=u.id_rozhodci1 AND r.status='ok'
LEFT JOIN karty zk ON u.id_utkani=zk.id_utkani AND zk.udalost='zk'
LEFT JOIN karty ck ON u.id_utkani=ck.id_utkani AND ck.udalost='ck'

WHERE u.sezona='2013' AND u.soutez='Zima'
GROUP BY u.id_rozhodci1

ORDER BY pocet DESC, cervene DESC, zlute DESC

Tento dotaz vyhodí seznam rozhodčích, počet odpískaných zápasů a počet rozdaných karet. Nicméně počet zápasů nikdy nesouhlasí, díky těm LEFT JOINům se vždy připočte +1


V DB: takto
utkani
========
zapas
zapas

karty
========
zk
zk

rozhodci
========
rozhodci


Mělo bý to vrátit
============
rozhodčí | 2 ZK | 0 CK | 2 utkani

Vrací mi to pořád 3 utkání, než se pustím do totálního přepisování (dotazu nebo aplikace) nemá někdo tucha jak to inteligentně a nenáročně fixnout, mě to dneska nemyslí .. :|
Kajman
Profil
Kcko:
Nechme to být :)

Pokud to je svižné, tak je nejjednodušší řešení nechat dotaz být.

K druhému dotazu...
count(distinct u.id_utkani) AS pocet
Obdobně bude potřeba použít distinct i na karty (podle pk).
Kcko
Profil
Kajman:
DISTINCT funguje. Tedy pouze tvůj navržený, pokud jej přidám i ke kartám ukazuje to špatný počet karet. (Místo 2 ZK, ukazuje 1 ZK).

Nerozumím tomu ovšem ... můžu požádat o vysvětlení

Edit: Přidal jsem 1 CK

COUNT( DISTINCT zk.udalost) AS zlute, 
COUNT( DISTINCT ck.udalost) AS cervene, 
COUNT( DISTINCT u.id_utkani) AS pocet, 

A výsledek je 2 utkani, 1 ZK, 1 CK, což je špatně správně to je 2-2-1

Ještě nějaká idea?
Kajman
Profil
Ta poslední věta znamená, že máš použít distinct nad primárním klíčem tabulky karty.
Kcko
Profil
Kajman:
Funguje díky. Já jsem si ten dotaz rozepsal, abych viděl co ty LEFT JOINy vytvoří a je to takto

řádek - hodnoty
řádek - hodnoty
řádek - same NULL hodnoty (to v mém případě je ten / byl ten problém).

Jak se tady tedy zachová ten count distinct, snažím se to pochopit, ale nedocvakne mi to. Každopádně díky.
Kajman
Profil
Ten řádek s null hodnotou nebyl problém, problémem pro sčítání byly ty dva řádky předtím, kdy se jednomu zápasu přiřadily dvě karty. A kdyby tam byly např. ještě tři červené karty, řádků s jedním zápasem by bylo 6.

Distinct v count počítá pouze jedinečné nenullové hodnoty. Viz. manuál.
Kcko
Profil
Tak jo bezva, děkuji.

Vaše odpověď

Mohlo by se hodit

Odkud se sem odkazuje


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0