Diskuze: Rekurzivní počítání článků v sekcích

PHP PHP Rekurzivní počítání článků v sekcích American English version English version

Avatar
David Čápka
Tým ITnetwork
Avatar
David Čápka:

Zdravím, již chvilku si lámeme hlavu nad tím, jak zobrazovat počty článků v sekcích tak, aby se zohlednilo zanoření několika sekcí do sebe. Příklad:

V sekci "HTML" je podsekce "HTML manuál" a ten bych moc rád tématicky rozdělil do podsekcí jako např. "Tabulky" nebo "Odstavce". Když bude v tabulkách 5 článků a v odstavcích 10, mělo by se u sekci HTML manuál zobrazit, že obsahuje 15 článků, teď by se tam zobrazilo, že obsahuje 2 (tedy ty 2 sekce tabulky a odstavce).

Jsem smířen s tím, že řešení nebude hezké :) Díky za jakýkoli nápad.

Odpovědět 10.11.2012 13:57
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Kit
Redaktor
Avatar
Odpovídá na David Čápka
Kit:

Rekurze se v SQL dělá blbě, resp. nedá se udělat efektivně. Asi to bude chtít mírnou denormalizaci a přidat do podsekcí sloupec s počtem článků. Tento sloupec pak aktualizovat např. triggerem při manipulaci s články.

Nahoru Odpovědět 10.11.2012 14:07
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Kit
David Čápka:

Díky za reakci. Toto řešení nás napadlo, ale když došlo na implementaci, nějak jsme se na tom zasekli, mám hrozně nerekurzivní myšlení :) Hlavně nevím, jak to obnovovat, předpokládám, že celé najednou by to trvalo dlouho, čili bychom potřebovali metodu, která nám refreshne počet článků u 1 sekce a všech jejich nadsekcí. Znamená to, že máme udělat refresh té jedné sekce a potom si hodit querku, jestli ta sekce není náhodou do nějaké vnořená a pokud ano, celou akci opakovat? Naštěstí máme vazbu sekce-článek jen 1:N.

Nahoru Odpovědět 10.11.2012 14:25
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Kit
David Čápka:

Hlavně mi tam chybí hodně informací, možná bych to potřeboval nejdříve celé spočítat nějakým skriptem a dalším jen refreshovat jednu sekci, co se změnila.

Nahoru Odpovědět 10.11.2012 14:35
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Kit
Redaktor
Avatar
Odpovídá na David Čápka
Kit:

Myslel jsem to tak, že by se např. při přidání článku do sekce inkrementoval čítač v sekci, následně by se inkrementoval i čítač v nadřízených sekcích až ke kořeni.

Bohužel na takové opičky nejsou SQL databáze stavěny. Jedině snad přes ten trigger.

Ještě mě napadla jedna varianta: Natáhnout seznam sekcí (stačí jen id a parent_id), průchodem od listu ke kořeni vybrat id sekcí (např. 5, 18, 200) a pak už jen

UPDATE sekce SET pocet=pocet+1 WHERE id IN (5, 18, 200);
Nahoru Odpovědět 10.11.2012 14:52
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
Kit
Redaktor
Avatar
Odpovídá na David Čápka
Kit:

Zkusil jsem to udělat tím triggerem, ale bohužel nezvládne rekurzi.

Nahoru Odpovědět 10.11.2012 17:00
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
Kit
Redaktor
Avatar
Odpovídá na David Čápka
Kit:

Ještě doplním, že v SQLite to s tím triggerem funguje parádně.

Nahoru Odpovědět 10.11.2012 17:27
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Kit
David Čápka:

Ony právěže ty sekce nemají parrent_id. Musím to nějak denormalizovat asi. Současný stav je následující:

tabulka sekce obsahuje sekce spolu s informací v jakém jazyce jsou zdrojové kódy v sekci. Dále je tu odkaz na článek, který sekci reprezentuje.

článek má potom informaci do které sekce patří (což může jako článek obyčejný i jako článek reprezentující sekci). Čili já z tabulky sekcí nezjistím, kdo je rodič, musím tam najoinovat článek. A to jsem chtěl ještě vazbu rozšířit na M:N, to by to už asi úplně pohřbilo :)

Nahoru Odpovědět 10.11.2012 17:38
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Kit
Redaktor
Avatar
Odpovídá na David Čápka
Kit:

Viděl bych to na zrušení tabulky sekce. Informace o sekcích by pak byly jako další záznamy mezi články. Článek by měl své id a parent by označoval sekci. Sekce by měla své id a parent by odkazoval na nadřízenou sekci. Nejvyšší sekce by měly parent=null.

Nahoru Odpovědět 10.11.2012 17:46
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
Kit
Redaktor
Avatar
Odpovídá na David Čápka
Kit:

Jen tak pro zajímavost malá ukázka, jak to funguje v SQLite.

PRAGMA recursive_triggers = on;
CREATE TABLE sekce(id integer primary key autoincrement, parent int, nazev text, pocet int);
INSERT INTO "sekce" VALUES(1,NULL,'PHP',0);
INSERT INTO "sekce" VALUES(2,NULL,'C#',0);
INSERT INTO "sekce" VALUES(3,8,'Java',0);
INSERT INTO "sekce" VALUES(4,1,'Databaze v PHP',0);
INSERT INTO "sekce" VALUES(5,1,'Vyjimky v PHP',0);
INSERT INTO "sekce" VALUES(6,3,'Java na desktopu',0);
INSERT INTO "sekce" VALUES(7,3,'Java na serveru',0);
INSERT INTO "sekce" VALUES(8,NULL,'sekce pro Javu',0);
CREATE TRIGGER tr_sekce UPDATE OF pocet ON sekce
   BEGIN
   UPDATE sekce SET pocet=pocet-old.pocet+new.pocet WHERE sekce.id=old.parent;
   END;

Při aktualizaci pocet např. u id=7 se aktualizuje i id=3 a 8.

Nahoru Odpovědět 10.11.2012 18:09
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Kit
David Čápka:

A nebude to moc denormalizované? Sekce bude mít navíc počet článků uvnitř, titulek (je často jiný, než článku), jazyk a ještě jsem plánoval další vlastnost, která by určovala od jakého čísla číslovat články. Tak by se daly udělat navazující seriály přes několik sekcí a šlo by mezi díly jednoduše řadit další bez nutnosti manuálního přečíslování. To jsou 4 prázdné sloupce u většiny článků, už teď jich má 25 :)

Na tu vazbu M:N se tedy asi vykašlu, ušetří to hodně problémů a nechceme jen psát redakční systém :)

Nahoru Odpovědět 10.11.2012 18:15
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Kit
Redaktor
Avatar
Kit:

Počet článků bude u článku roven 1, sloupec s titulkem bude sdílený (sekce je v jiném záznamu) jazyk by měl být u každého článku, číslování článků je zdrojem problémů. Tedy bez prázdného sloupce.

Z článku se snadno může stát sekce. To nezní špatně.

Navazující seriály se dají udělat přes URL v článku či sekci.

Editováno 10.11.2012 18:28
Nahoru Odpovědět 10.11.2012 18:24
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
Kit
Redaktor
Avatar
Odpovídá na David Čápka
Kit:

Sekce jsou uzly a články jsou listy stromu. V principu není velký rozdíl mezi uzlem a listem a sjednocení přístupu zpravidla vede ke zjednodušení aplikace.

Nahoru Odpovědět 10.11.2012 18:34
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Kit
David Čápka:

A jakým způsobem udělám naplnění toho počtu článků v sekci poprvé, když bude ten sloupec ještě prázdný? Nějak mě nenapadá za který konec to vzít :)

Číslování článků mi tu chybí i když je to další komplikace, ty seriály by lépe vynikly. Máme sloupec, kde je pořadové číslo článku v sekci (tak jim určujeme pořadí výpisu, máme javascriptový widget, kde je myší seřadíme a on je tak očísluje), asi by se to dalo využít pro tento účel a s omezením, že by samostatné články nebyly mezi lekcemi, by to mohlo docela fungovat.

Nahoru Odpovědět 10.11.2012 18:53
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Kit
Redaktor
Avatar
Odpovídá na David Čápka
Kit:

To nebude zas tak složité. Záleží na tom, jestli do tabulky prvně uložíš sekce nebo články. Případně tam dáš všechno, necháš to propočítat a aktivuješ trigger.

Číslování článků můžeš udělat ve výstupní šabloně, v DB to být nemusí. Alespoň nebudeš muset řešit přečíslování.

Číslování sekcí by také mohlo mít svůj význam.

Nahoru Odpovědět 10.11.2012 19:16
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Kit
David Čápka:

No já nevím jak to nechat propočítat :) Potřeboval bych začít od těch nejnižších sekcí, ale jak je poznám?

V šabloně by to šlo v seznamu článků, ale když si ho otevřu, ten článek už neví, jak byl předtím vypsán. Sekcím jsem chtěl dát číslovací offset, abych mohl dělat seriály přes sekce.

Nahoru Odpovědět 10.11.2012 19:20
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Kit
Redaktor
Avatar
Odpovídá na David Čápka
Kit:

Každý článek bude mít rodiče - sekci. Projedeš si selectem všechny články GROUP BY parent. Tím získáš počty v nejnižších sekcích. Aktualizuješ. Tak to projdeš až ke kořeni. Není to sice tak pohodlné jako rekurze, ale fungovat to bude.

Na konci článku je dobré vypsat seznam článků v sekci. Přitom se dá zjistit pořadí aktuálního článku (a ten jeden nedělat jako odkaz).

Nahoru Odpovědět 10.11.2012 19:31
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Kit
David Čápka:

Jsem z toho jelen :) GROUP BY jsem nikdy moc nepochopil a nevím, jak udělat, aby to do toho počtu nedávalo samotné sekce. No je to každopádně hrůza, asi zatím spíchnu nějaký work-around. Vnoření tolika sekcí do sebe tak, aby to bylo vidět, plánuji jen na 2 místech, tak to asi zatím zadám manuálně a bude :D

Na konec článku chci určitě dát nějaký widget, vídal jsem "podobné články", kompletní seznam sekce jsem ještě neviděl. Možná by bylo dobré 3 odkazy: předchozí, další a sekce.

Nahoru Odpovědět 10.11.2012 19:53
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Avatar
Kit
Redaktor
Avatar
Odpovídá na David Čápka
Kit:
SELECT parent, count(*) AS pocet FROM clanek WHERE NOT je_sekce GROUP BY parent;

Tohle si dáš do pomocné tabulky, podle které aktualizuješ. Pak si podle ní vyhledáš všechny rodiče aktualizovaných záznamů, zase aktualizuješ a tak dál, dokud nebude prázdná. V tom selectu už nebude count(*), ale sum(pocet).

Kompletní seznam článků sekce najdeš třeba na linuxsoft.cz.

Nahoru Odpovědět 10.11.2012 20:07
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Kit
David Čápka:

Díky, zatím to nějak nahackuji a potom se k tomu vrátím :)

Nahoru Odpovědět 10.11.2012 21:25
Miluji svou práci a zdejší komunitu, baví mě se rozvíjet, děkuji každému členovi za to, že zde působí.
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 20 zpráv z 20.