Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Diskuze: Nekonečný počet podkategorii

Aktivity
Avatar
Neaktivní uživatel:23.7.2017 3:16

Hoj,

mám problém s návrhem struktury databáze pro nekončený počet podadresáru, vždy jsem využívál max. 1, ale teď potřebují ten limit dat pryč.

Náhledný příklad co vlastně potřebují:

domena.cz/kate­gorie/podkate­gorie1/podkate­gorie2
domena.cz/kate­gorie/podkate­gorie1/podkate­gorie2/podkate­gorie3/podkate­gorie4

Napadlo mě, že bych vytvořil tabulku s kategoriemi, a s podkategoriemi

Tabulku s podkategoriemi bych propojil s kategoriemi pomoci relace, ale to mam limit na 1 podkategorii.

Hlavně to potřebují pomocí relace, jelikož budu potřebovat získat veškeré podkategorie dané kategorie.

Jak tohle řešíte? Díky

Editováno 23.7.2017 3:19
Odpovědět
23.7.2017 3:16
Neaktivní uživatelský účet
Avatar
Deart
Tvůrce
Avatar
Deart:23.7.2017 8:06

Můžeš to vyřešit tak, že všechny kategorie (i podkategorie) dáš do jedné tabulky a poté akorát vytvoříš tabulku vztahů:

Název nadřazené kategorie Název podkategorie
kategorie1 podkategorie1
podkategorie1 podkategorie2
podkategorie2 podkategorie3
Editováno 23.7.2017 8:07
 
Nahoru Odpovědět
23.7.2017 8:06
Avatar
Paul
Člen
Avatar
Odpovídá na Neaktivní uživatel
Paul:24.7.2017 9:04

Pokud bys to řešil na Oracle, dá se to vyřešit celkem pohodlně pomocí jedné tabulky a funkce LISTAGG.
Tabulka by obsahovala následující:

nazev_kategorie id_podkategorie nazev_podkategorie
kategorie1 1 podkategorie1
kategorie1 2 podkategorie2
kategorie1 3 podkategorie3
kategorie2 1 podkategorie1
kategorie2 2 podkategorie2

Sloupec id_podkategorie je tu pouze pro potřeby řazení ve funkci, abys měl na výstupu kategorie správně seřazené.

Funkce by pak vypadala následovně:

SELECT LISTAGG(nazev_podkategorie, '/') WITHIN GROUP (ORDER BY id_podkategorie)
FROM tabulka_kategorii
WHERE nazev_kategorie = 'kategorie1';

Pokud to děláš na MS SQL, tak něco podobného funguje tuším od verze 2017.
V dřívějších verzích se na to musí jít trochu oklikou, ale taky se to dá udělat.

Na jiných databázích jsem to nikdy neřešil, ale určitě to taky půjde :-)

 
Nahoru Odpovědět
24.7.2017 9:04
Avatar
Neaktivní uživatel:25.7.2017 7:35

Hledal jsem po netu a nasel tohle. Vypada to, ze je to to co potrebuji(pokud teda nenarazim na neco co mi tahle moznost zneprijemni praci)

CREATE TABLE Category (
    id INT AUTO_INCREMENT NOT NULL,
    parent_id INT DEFAULT NULL,
    PRIMARY KEY(id)
) ENGINE = InnoDB;
ALTER TABLE Category ADD FOREIGN KEY (parent_id) REFERENCES Category(id);

Vytvori se kategorie bez parent_id, potom podkategorie s parent_id a podle toho se tahaji podaktegorie atd..
Uvidime.

Editováno 25.7.2017 7:36
Nahoru Odpovědět
25.7.2017 7:35
Neaktivní uživatelský účet
Avatar
Paul
Člen
Avatar
Odpovídá na Neaktivní uživatel
Paul:25.7.2017 9:17

No tak se to dá udělat, ale myslím že jen v případě, kdy budeš mít pro všehcny kategorie vždy stejný počet podkategorií. Jak víš kolikrát na sebe máš joinovat tu tabulku?
Musel by sis někde v proměnné uchovávat počet podkategorií a podle toho pak generovat dynamické SQL.
Nebo sem zkus napsat ten join, jak jsi to myslel.

Editováno 25.7.2017 9:18
 
Nahoru Odpovědět
25.7.2017 9:17
Avatar
Milan Gallas
Tvůrce
Avatar
Milan Gallas:28.7.2017 18:55

sloupce: id, parent_id, name ...........

pak můžeš využít něco takového

WITH category_tree AS
        (
        SELECT  *, 0 AS category_level
        FROM    dbo.category
        UNION ALL
        SELECT  c.*, category_level + 1 as category_level
        FROM    category_tree ct
        JOIN    dbo.category AS c
        ON      c.Id = ct.parent_id
        )
SELECT  *
FROM    category_tree
Editováno 28.7.2017 18:55
 
Nahoru Odpovědět
28.7.2017 18:55
Avatar
Paul
Člen
Avatar
Odpovídá na Milan Gallas
Paul:30.7.2017 21:49

Myslím, že tohle nebude fungovat.
V definici category_tree selectuješ z category_tree.

 
Nahoru Odpovědět
30.7.2017 21:49
Avatar
plelovsky
Člen
Avatar
Odpovídá na Paul
plelovsky:31.7.2017 16:03

Myslím, že tohle nebude fungovat.
V definici category_tree selectuješ z category_tree.

V tom problém není - jedná se o tzv. Recursive CTE - viz např. https://technet.microsoft.com/…ql.105).aspx
Je to nástroj po práci s hierarchickými daty v MS SQL.

Ale tak, jak je to v příspěvku výše uvedeno to fungovat nebude, protože jednak jsou tam chyby a především tím nezíská to co je požadováno v zadání - veškeré podkategorie dané kategorie.
Bylo by to nějak takto:

WITH category_tree AS
(
    SELECT *, category_level = 0, id AS root_id
    FROM category
    WERE parent_id IS NULL -- touto podminkou vyberu nejvyssi uroven, ktera nema parenta

    UNION ALL

    SELECT c.*, category_level = ct.category_level + 1, ct.root_id
    FROM category AS c
        INNER JOIN category_tree AS ct ON ct.id = c.parent_id
)
SELECT *
FROM category_tree
WHERE root_id = @id -- @id predstavuje id pozadovane kategorie
 
Nahoru Odpovědět
31.7.2017 16:03
Avatar
David Hynek
Tvůrce
Avatar
Odpovídá na Neaktivní uživatel
David Hynek:31.7.2017 21:43

K tomu se pouziva neco cemu se rika Traverzovani kolem stromu. Funguje to tak, ze mas polozku, ktera ma v sve ID (neni to cislo zaznamu) a pak dva sloupce od a do. Kdyz vytvoris podpolozku, priradis ji cislo ID o jedno vetsi nez je ID polozky a vsechny ID co jsou pod nim zvednes o jedno. Vcetne zaznamu od a do. Vytvori se tak struktura, ktera se pouziva u diskusnich for se zanorenymi komentari. Jednou se mi podarilo ji skutecne rozebehnout, ale blbe se v tom listuje. A k pochopeni je to taky vorech vorechovic. Pekne a spravneji nez ja to u sebe popisuje Jakub Vrana. Ale nechces li si zivot komplikovat moc, jdi prostsi cestou. Treba vetsim poctem tabulek, kde bude mit kazda uroven svou. A pocitam, ze dale nez do 10 zanoreni se nedostanes. Budes mit pak 10 tabulek, kde v kazde vyssi bude odkaz na rodice. Jestli nebudes mit milion podkategorii, pak by to slo dat i do jedne tabulky, kde budes mit sloupec kategorie a sloupec urovne zanoreni a sloupec rodice.

Editováno 31.7.2017 21:46
Nahoru Odpovědět
31.7.2017 21:43
Čím víc vím, tím víc věcí nevím.
Avatar
Peter Trcka
Člen
Avatar
Odpovídá na Neaktivní uživatel
Peter Trcka:2.8.2017 10:23

Ahoj, ja by som to riesil kombinaciou uz spomenutych rieseni. Nie je to uplne programatorsky spravne, ale podla mna jednoduche riesenie tvojho problemu. Nemam moc rad zlozite sql

1. vytvor si tabulku, ako pises, kam sa budu ukladat vsetky zaznamy

CREATE TABLE Category (
    id INT AUTO_INCREMENT NOT NULL,
    name VARCHAR(50),
    parent_id VARCHAR(60),
    PRIMARY KEY(id)
) ENGINE = InnoDB;

velkost VARCHAR potom bude zavisiet podla toho, kolko bude zaznamov v tabulke, a kolko budes pocet podkategorii (bude to treba hlidat, aby nedoslo k preteceniu).

Pri pridavani musis vediet parent_id, a preto by som si ukladal do parent_id rovno celu strukturu. Vyhnes sa tak zlozitym repeatom v sql. Ako to myslim:

id name parent_id
1 domena.cz NULL
2 kat-1 1
3 podkat-1 1-2
4 kat2 1
5 podkat-2 1-4
6 podpodkat-2 1-4-5

Pri vytvarani novej (pod)kategorie vies parent_id kde kam zaradis novu kategoriu(dome­na.cz, alebo nejaka podkategoria). Problem je, ze poznas len parent_id a nevies celu strukturu az k domena.cz. Preto si tu strukturu uloz, sice to zaberie viac miesta, ale na rychlost to az taky vplyv mat nebude.

povedzme ze chces pridat novu podkategoriu, ktorej parent_id = 6 ( bude patrit do podpodkat-2).

$parent_id_str = execMyQuery('Select parent_id from category where id = ' . $parent_id);
$parent_id_str .= "-" .$parent_id;
execMyQuery("INSERT INTO category (id, name, parent_id) VALUES ('','$newCatName','$parent_id_str')");

najprv ziskas parent_id_str z tabulky, to zretazis s id nadkategorie a to potom ulozis ako novy zaznam. execMyQuery je nejaka implicitna funkcia ktora vykona sql query, a vrati ti hodnotu.

ked si budes chciet vytiahnut strukturu:

$result = execMyQuery('Select parent_id from category where id = ' . $category_id);
$result = explode($result, '-');
$condition = "id = '". implode($result, "' OR id ='") . "'";
$categoryTree = execMyQuery("SELECT id, name FROM category WHERE $condition ORDER BY id");

a teraz budes mat v categoryTree pekne v poli v poradi domena.cz , kat-2, podkat-2, podpodkat-2.
Na rychlost to nema vplyv lebo sa vzdy odkazujes cez primarne kluce, ktore su indexovane a nepouzivas fulltext vyhladavanie. ako oddelovac mozes pouzit cokolvek, pomolcku, podtrznik, pismenko, zvislitko, ...

je treba osetrit to retazenie pre kategoriu priamo pod domena.cz, a mnoho dalsich drobnosti

Berte to ako myslienku. Je to pisane z hlavy, tak to berte s rezervou.

Editováno 2.8.2017 10:25
 
Nahoru Odpovědět
2.8.2017 10:23
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 10 zpráv z 10.