Oznámení
Hlavobol obecný, DIBI fluent, problem s join a SUM
před 8 lety
- demonic
- Člen | 20
Zdravím kolegové a zároven' moc prosím o radu.
DB je rozdělena na 6 úrovní zakázky, každá nese nazev, id a cizí klíč
z vyšší úrovně(potomek rodič)
5 úroven' má ještě tabulku level5_zakazka_polozky ze které se čerpají
všechna data.
Všechny záznamy z level5_zakazka_polozky Mají přiděleno level6_zakazka_id
z intervalu 1–7 (1 materiál MA, 2 Mzdy MZ, 3 Stroje ST atpod.)
Předchozí dotaz funguje ale trvá minutu a déle na poměrně málo
záznamech (cca 15 000) jak by jste jej optimalizovali?
Potřebuji to v zápisu DIBIFLUENT protože je to pro gridito.
V klasickém query bych to asi nějak spáchal ale tady mě nenepadlo nic
lepšího než tahle šílenost..
Prosím o pomoc
public function __construct(\DibiConnection $db, $id = NULL)
{ //nakl.sumaL5 as naklady
parent::__construct($db->select("l2.*, COUNT(p.id) as row_count,
SUM(l5_polozky.mnozstvi * l5_polozky.cena_mj) as naklady,
SUM(l5_polozkyMA.mnozstvi * l5_polozkyMA.cena_mj) as ma,
SUM(l5_polozkyMZ.mnozstvi * l5_polozkyMZ.cena_mj) as mz,
SUM(l5_polozkyST.mnozstvi * l5_polozkyST.cena_mj) as st
atd ..
")->from("::level2_zakazka l2")->where("level1_zakazka_id= %i", $id)->groupBy("l2.id")
//->select('(SELECT SUM(mnozstvi*cena_mj) FROM level5_polozky WHERE level6_zakazka_id = 2 AND level5_zakazka_id = l5.id) as naklady')
//->leftJoin('(SELECT * FROM ::level5_polozky WHERE level6_zakazka_id = 3 GROUP BY l5.id) l5_polozkyST')->on('l5.id = l5_polozkyST.level5_zakazka_id ')
->leftJoin('::level3_zakazka l3')->on('l2.id = l3.level2_zakazka_id ')
->leftJoin('::level4_zakazka l4')->on('l3.id = l4.level3_zakazka_id ')
->leftJoin('::level5_zakazka l5')->on('l4.id = l5.level4_zakazka_id ')
->leftJoin('::level5_polozky l5_polozky')->on('l5.id = l5_polozky.level5_zakazka_id ')
->leftJoin('(SELECT * FROM ::level5_polozky WHERE level6_zakazka_id = 1) l5_polozkyMA')->on('l5_polozky.id = l5_polozkyMA.id ')
->leftJoin('(SELECT * FROM ::level5_polozky WHERE level6_zakazka_id = 2) l5_polozkyMZ')->on('l5_polozky.id = l5_polozkyMZ.id ')
->leftJoin('(SELECT * FROM ::level5_polozky WHERE level6_zakazka_id = 3) l5_polozkyST')->on('l5_polozky.id = l5_polozkyST.id ')
->leftJoin('(SELECT * FROM ::level5_polozky WHERE level6_zakazka_id = 4) l5_polozkyD')->on('l5_polozky.id = l5_polozkyD.id ')
->leftJoin('(SELECT * FROM ::level5_polozky WHERE level6_zakazka_id = 5) l5_polozkyC')->on('l5_polozky.id = l5_polozkyC.id ')
->leftJoin('(SELECT * FROM ::level5_polozky WHERE level6_zakazka_id = 6) l5_polozkyN')->on('l5_polozky.id = l5_polozkyN.id ')
->leftJoin('(SELECT * FROM ::level5_polozky WHERE level6_zakazka_id = 7) l5_polozkySL')->on('l5_polozky.id = l5_polozkySL.id ')
->leftJoin('::percentage p')->on('l5.id = p.level5_zakazka_id ')
);
}
Zkoušel jsem i styl zápisu SUM(DISTINCT (SELECT SUM(mnozstvi*cena_mj, to sice dává ‚správné hodnoty‘ avšak díky DISTINCT pouze do momentu, kdy se neobjeví stejné sumy.
Děkuji za jakoukoliv pomoc
Editoval demonic (30. 4. 2011 21:01)
před 8 lety
- Milo
- Nette Core | 1119
První co mě napadá je použít vícenásobnou podmínku joinu namísto subselectu (pokud to DB umí).
dibi::query("
SELECT
l2.*,
COUNT(p.id) as row_count,
SUM(l5_polozky.mnozstvi * l5_polozky.cena_mj ) as naklady,
SUM(l5_polozkyMA.mnozstvi * l5_polozkyMA.cena_mj) as ma,
SUM(l5_polozkyMZ.mnozstvi * l5_polozkyMZ.cena_mj) as mz,
SUM(l5_polozkyST.mnozstvi * l5_polozkyST.cena_mj) as st
FROM
::level2_zakazka l2
LEFT JOIN ::level3_zakazka l3 ON l2.id = l3.level2_zakazka_id
LEFT JOIN ::level4_zakazka l4 ON l3.id = l4.level3_zakazka_id
LEFT JOIN ::level5_zakazka l5 ON l4.id = l5.level4_zakazka_id
LEFT JOIN ::level5_polozky l5_polozky ON l5.id = l5_polozky.level5_zakazka_id
LEFT JOIN ::level5_polozky l5_polozkyMA ON l5_polozky.id = l5_polozkyMA.id AND level6_zakazka_id = 1
LEFT JOIN ::level5_polozky l5_polozkyMZ ON l5_polozky.id = l5_polozkyMZ.id AND level6_zakazka_id = 2
LEFT JOIN ::level5_polozky l5_polozkyST ON l5_polozky.id = l5_polozkyST.id AND level6_zakazka_id = 3
LEFT JOIN ::level5_polozky l5_polozkyD ON l5_polozky.id = l5_polozkyD.id AND level6_zakazka_id = 4
LEFT JOIN ::level5_polozky l5_polozkyC ON l5_polozky.id = l5_polozkyC.id AND level6_zakazka_id = 5
LEFT JOIN ::level5_polozky l5_polozkyN ON l5_polozky.id = l5_polozkyN.id AND level6_zakazka_id = 6
LEFT JOIN ::level5_polozky l5_polozkySL ON l5_polozky.id = l5_polozkySL.id AND level6_zakazka_id = 7
LEFT JOIN ::percentage p ON l5.id = p.level5_zakazka_id
WHERE
level1_zakazka_id= %i", $id, "
GROUP BY
l2.id
");
Anebo takto, pokud umí DB převést boolean na INT.
dibi::query("
SELECT
l2.*,
COUNT(p.id) as row_count,
SUM(l5_polozky.mnozstvi * l5_polozky.cena_mj ) as naklady,
SUM(l5_polozky.mnozstvi * l5_polozky.cena_mj * (level6_zakazka_id = 1)) as ma,
SUM(l5_polozky.mnozstvi * l5_polozky.cena_mj * (level6_zakazka_id = 2)) as mz,
SUM(l5_polozky.mnozstvi * l5_polozky.cena_mj * (level6_zakazka_id = 3)) as st
FROM
::level2_zakazka l2
LEFT JOIN ::level3_zakazka l3 ON l2.id = l3.level2_zakazka_id
LEFT JOIN ::level4_zakazka l4 ON l3.id = l4.level3_zakazka_id
LEFT JOIN ::level5_zakazka l5 ON l4.id = l5.level4_zakazka_id
LEFT JOIN ::level5_polozky l5_polozky ON l5.id = l5_polozky.level5_zakazka_id
WHERE
level1_zakazka_id= %i", $id, "
GROUP BY
l2.id
");