Autor Zpráva
fm_pr
Profil *
Zdravím,

mějme pro jednoduchost jednu jedinou tabulku kategorie a u ní jsou v jednom sloupci i vypsané počty produktu v ní:
id
parent_id
count_articles - v tomto sloupci je pro jednoduchost už předpřipraven počet produktu v této kategorii

PRIKLAD tabulky:
1;NULL;0
2;1,1
3;1;3
4;2;10
5;2;5

graf pro tabulku viz. výše vypadá takto:
KATEGORIE1 (obsahuje 0 clanku)
-KATEGORIE2 (obsahuje 1 článek)
--KATEGORIE4 (obsahuje 10 článků)
--KATEGORIE5 (obsahuje 5 článků)
-KATEGORIE3 (obsahuje 3 články)

snažím se nyní vymyslet MySQL dotaz (ne kód v php!), který mě vrátí kategorii a počet článků VČETNE počtu článků v jejím podstromu, tedy pro příklad výše by měl být výsledek:

1;19
2;16
3;3
4;10
5;5


Prosím nepište rady typu předělej celou databázi nebo to naprogramuj v php pomocí rekurze ;)
Jinak nemusí to být časově nijak extra optimalizovaný, může to být klidně nějaká procedura s rekurzí atd... ale musí to vyplyvnout tu tabulku...
vítěz má flašku ;)
tiso
Profil
problém takto uloženého stromu kategórií je ten, že musíš vedieť hĺbku vnorenia. Pre tvoj prípad:
SELECT lvl1.id, lvl1.count_articles + IFNULL(SUM(DISTINCT lvl2.count_articles), 0) + IFNULL(SUM(DISTINCT lvl3.count_articles), 0) count
FROM categories lvl1
LEFT JOIN categories lvl2 ON lvl1.id = lvl2.parent_id
LEFT JOIN categories lvl3 ON lvl2.id = lvl3.parent_id
GROUP BY lvl1.id;
fm_pr
Profil *
tiso:
v tom je právě problém, hloubka vnoreni je obecne n...

neni to zadna legrace toto vyresit a ani na zahranicnich forech nikdo nenabizi zadne funkci reseni... vsichni odkazuji na rekurze a klazuli WITH, coz v mysql neni implementovany...

dneska jdu touto cestou:

1) nacist si pocty clanku do jednotlivych kategorii (to je primitivni a v mem zadani uz je tento krok preskocen)
2) projit kurzorem vsechny listy stromu kategorii a postupne dalsim kurzorem pro kazdy uzel na ceste od kazdeho listu stromu k jeho vrcholu pricitat aktualni pocet clanku

no neni to zadna legrace a to jsem veril, ze uloha "vrat pocty clanu v kategoriich vcetne jejich podkategoii" neni nijak slozita a davno vyresena...

no kdyby mel nekdo univerzalni reseni, sem s nim :)
Kajman
Profil
fm_pr:
kdyby mel nekdo univerzalni reseni, sem s nim

Přejít na databázi, která rekurzivní dotazy podporuje. Určitě to půjde v postgresql nebo oracle.

Ukázka pro oracle
SELECT id,
       SUM(count_articles) count_articles
FROM   (SELECT connect_by_root id id,
               count_articles
        FROM   kategorie
        CONNECT BY NOCYCLE PRIOR id = parent_id)
GROUP  BY id
ORDER  BY id

Ukázka pro postgresql
WITH RECURSIVE s AS
(
       SELECT k.id,
              k.parent_id,
              k.count_articles,
              k.id gid
       FROM   kategorie k
       UNION
       SELECT ks.id id,
              s.parent_id,
              ks.count_articles,
              s.gid
       FROM   kategorie ks
              JOIN s
                ON ks.parent_id=s.id )
SELECT   gid                 id,
         SUM(count_articles) count_articles
FROM     s
GROUP BY gid
ORDER BY gid

V mysql si můžete leda pomoci pomocnými sloupci pro traverzování kolem stromu, pak by to jít mělo nějak takto
SELECT k.id,
       Sum(s.count_articles) count_articles
FROM   kategorie k
       JOIN kategorie s
         ON k.lft <= s.lft
            AND k.rgt >= s.rgt
GROUP  BY k.id
ORDER  BY k.id
fm_pr
Profil *
tak po dvou třech dnech jsem přidal lft a rgt a v kombinaci s původním parent_id je to celkem mocný nástroj (parent_id vše krásně jistí, kdyby se náhodou lft a rgt nějak rozsypalo). Bohužel jsem přišel na velmi nepříjmenou drobnost - jeden článek mohu mít zařazen do více kategorií. S tím jsem v zadání nepořítal a pokud jsem psal, že KATEGORIE4 obsahuje 10 a KATEGORIE5 obsahuje 5 článků, úplně jsem zapomněl na tom, že tabulka články kategorie je M:N, takže jeden článek je ve více kategoriích, takže v kategorii 4 a 5 rlzných článků, těch různých článků může být třeba jen šest (respektivě minimálně 5)

máte nápad jak to do funkčního kódu zapracovat?

SELECT k.id, k.name,
Sum(s.count_articles) count_articles
FROM _is_categories k
JOIN _is_categories s
ON k.lft <= s.rgt
AND k.rgt >= s.rgt
GROUP BY k.id
ORDER BY k.id


Tedy jak získat s.count_articles z tabulky např. articles_categories ?
Kajman
Profil
Pokud tedy opravdu nevadí, že to bude pomalejší, tak bych zkusil

SELECT k.id,
       k.name,
       Count(DISTINCT ac.article_id) count_articles
FROM   _is_categories k
       JOIN _is_categories s
         ON k.lft <= s.rgt
            AND k.rgt >= s.rgt
       LEFT JOIN articles_categories ac
              ON s.id = ac.category_id
GROUP  BY k.id
ORDER  BY k.id 


lft a rgt a v kombinaci s původním parent_id je to celkem mocný nástroj
Ještě se občas přidává předpočítaný level nebo hloubka zanoření.
fm_pr
Profil *
perfektní, skutečně to funguje... :)

ještě bych potřeboval jen přidat podmínku articles.active=1 (nyní se započítají počty všech článků v kategoriich, potřebuju omezit na jen aktivní články) a pokud pošlete adresu na fantommax zavinac seznam.cz , tak máte slíbenou flašku dle výběru :) nebo paypal ucet... ;)
Kajman
Profil
SELECT k.id,
       k.name,
       Count(DISTINCT a.id) count_articles
FROM   _is_categories k
       JOIN _is_categories s
         ON k.lft <= s.rgt
            AND k.rgt >= s.rgt
       LEFT JOIN articles_categories ac
              ON s.id = ac.category_id
       LEFT JOIN articles a
              ON ac.article_id = a.id
                 AND a.active = 1
GROUP  BY k.id,
          k.name
ORDER  BY k.id

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: