Autor Zpráva
Jcas
Profil *
Prosím o radu? Celý den přemýšlím, jak seskupit data z tabulek k sobě.
Napadlo mě vybírat řádky po jednou a vnoření cyklů while do sebe. Nevím, jestli je to správná cesta. Zatím řeším jednoho chovatele pro zpracování svých dat. Jestli ale použiju stejnou metodu pro zobrazování, tak to bude hoooodně sql dotazů.

Na ukázku mám dva cykly. Ve finále budou do sebe vnořeny 4.
1.Přepisuji si $radek - to asi nevadí, když hodnoty strkám do pole.?
2. To by možná šlo udělat rekurzívním voláním funkce?
3. $mysqli - je ve funkci viditelná, nebo se musí předávat?
4. Je to vůbec správný směr, jakým to dělat? (napřed jsem zkoušel vybrat všechna data a pak nějak zpracovat pole. Ale to jsem nepřišel na absolutně žádné řešení.


 /*
 Tabulka 'zvirata'
 |---id_zvirete---|---zvire---|---skupina---|
 
 příkl.
 |---1---|---Hlodavec---|---0---|      // úroveň 0 - skupina
 |---2---|--- Drůbež ---|---0---|
 |---3---|--- králík ---|---1---|    // úroveň 1 - zvíře
 |---4---|---Aljaška ---|---3---|    // úroveň 2 - plemeno
 |---5---|---  černý ---|---4---|    // úroveň 4 - barva
 
 // králík bude mít 'skupina'=null a 'id'=1(např.)
 // Aljaška bude mít 'skupina'=1

 -----------------------------------------------------------
 Tabulka 'chovy'
 |---id_chovu---|---id_chovatel---|---id_zvire---|
 
 příkl.
 |---1---|---1---|---1---|     (id, Pepa, hlodavec)
 |---1---|---1---|---3---|        (id, Pepa, králík)
 
 // `id_chovu` - identifikace zvířete. Hlodavec-králík-Aljaška-černá => stejné id.
 // "chovy['id_chovatel']" == "USER['id']"
 //"chovy['id_zvire']" == "zvirata['id_zvirete']"
 -------------------------------------------------------- */
      $sql = "SELECT `chovy`.*, `zvirata`.* 
      FROM `chovy` JOIN `zvirata`
      ON `chovy`.`id_zvire` = `zvirata`.`id_zvirete`
      WHERE `chovy`.`id_chovatel` = $id_user AND `zvirata`.`skupina` = 0";
      
    $res = $mysqli->query($sql);
        while ($radek = $res->fetch_assoc()) { 
        $skupina[] = $radek;    // $radek['id_zvirete'] == potomek(`zvirata`.`skupina`)
        
        // najdi potomka, který má stejný `id_chovu`
        $sql2 = "SELECT `chovy`.*, `zvirata`.* 
          FROM `chovy` JOIN `zvirata`
          ON `chovy`.`id_zvire` = `zvirata`.`id_zvirete`
          WHERE `chovy`.`id_chovatel` = $id_user 
          AND `zvirata`.`skupina` = ".$radek['id_zvirete'];    
          
          $res2 = $mysqli->query($sql);
            while ($radek = $res2->fetch_assoc()) {
                $zvire[] = $radek;
            }
        }
    $res->close();
juriad
Profil
OK, dostáváme se k ukládání stromů v databázi.
http://www.slideshare.net/billkarwin/sql-antipatterns-strike-back od strany 48 je přehled možností.
To co jsi navrhl je sice správně, ale jak jsi již zjistil, počet dotazů dramaticky narůstá; lze to sice vyřešit položením jediného dotazu, ale ten nebude zrovna efektivní (co úroveň to JOIN). Hlavní problém je však v tom, že nelze mít hierarchii libovolně hlubokou.

Z toho důvodu se často používá druhý způsob: „Nested Sets“ nebo česky „Traverzovaní kolem stromu“ od Jakuba Vrány.
Nevýhodou tohoto přistupu je jeho neintuitivnost, nemožnost dotazu na přímé potomky a hodně těžká modifikace existujícího stromu.

Ty dva další přistupy (popis cesty ke kořeni a tranzitivní uzávěr) mají také své problémy.
Pro možnosti použití se podívej na slide 77.

Mimochodem, zamysli se, zda opravdu má smysl zvířata kategorizovat až do takové hloubky; nestačí náhodou dvě úrovně: zvíře a plemeno?
Bude to i pohodlnější pro uživatele (nebude muset proklikávat tolik úrovní.
Jcas
Profil *
Bohužel pro specializaci oboru asi ty 4 úrovně potřebuji.
Barva je nutná, i když by mohla být pouze jako poznámka. Nemusí to být vyhledávací klíč, ale musí být ke zvířeti přidána.

A tu 4. úroveň mi udělala drůbež. Základ je holub, králík, drůbež a pak plemeno. Jenomže ta drůbež má dělení vodní, hrabavou a ty se pak dělí na slepice, perličky, kachny, husy.
Hrabavou a vodní mohu oželit. Drůbež-kachna, drůbež-slepice. Ale bohužel mi ta drůbež přihodila další úroveň.
Jcas
Profil *
Nerozumím FOREIGN KEY. Ještě jsem to nikdy nepoužil a u tabulek to nemám nastavený.
K čemu to je, když stejně se ta vazba dává vždy do dotazu?
ON tab1.id = tab2.id
WHERE tab1.id = tab2.id

Existuje třeba dotaz stylu: Vyber vše z tab1 a z tab2 a z tab3, pokud data patří k sobě, a uživatel = tab1.uživatel
Alphard
Profil
Zřejmě vůbec nevíte, co jsou indexy, takže např. Využití databázových indexů - Root.cz a praktický článek např. PHP triky - Ukázka použití indexů.
juriad
Profil
FOREIGN KEY jednoduše řečeno zajišťuje, že vazby v databázi budou v pořádku.
Například, pokud se nějaký záznam odkazuje na uživatele s id=1, tak takový uživatel bude nutně existovat; nepodaří se ti jej odstranit či změnit jeho id. Ty operace, které by nazbu narušily, skončí chybou.

FOREIGN KEY nijak nesouvisí s vlastním dotazem; tam si veškeré spojování musíš udělat sám. FOREIGN KEY jen zajistí, že se na data můžeš spolehnout. Navíc je užitečný jako dokumentace.

Některé nástroje dokáží z jeho existence ty vazby v aplikaci rovnou zrealizovat. Nebo naopak z diagramu vygenerovat celou databázi (příkazy CREATE TABLE).
Jcas
Profil *
Alphard, juriad: Děkuju - foreign key - pochopeno.
juriad: Děkuju za super odkaz na stromy. Studovl jsem do půlnoci a dnes od 5.
Ty dvě varianty uprostřed se mi vůbec nelíbí. Takže zbývá cros table.
Ale nejdu do toho. Něvěřím, že to zvládnu. Zvlášť, když si vezmu, jaké problémy mám s hloupým spojením dvou tabulek. Sice bych to s vaší pomocí poskládal, ale za půl roku bych se v tom asi vůbec nevyznal.

Takže bych se asi vrátil na dvě úrovně. Hlavní vyhledávací klíče jsou `zvíře` a `plemeno`, takže by to mělo stačit.
Jen nevím, jak vyřešit ty barvy a tu drůbež.
1. Možnost - barvu do poznámky, ale to bych musel hodit do tabulky `chovy`aby byla spjata s chovatelem. Drůbež do 3.tabulky a mohl bych to rozhodit na vodní a hrabavou.
2. Možnost - Mít tabulky 4.Některá plemena nemají barvy žádné a jiné strašně moc.
Výhodou této možnosti je, že by tyto tabulky mohly sloužit jako DB zvířat a mohl bych je použít jako seznam plemen, či použít u výstav.
Nechám si poradit. Mám jít do cross table, nebo udělat 4 tabulky?

ps. I když jsem se rozhodl to stáhnout na dvě úrovně (pokud nepůjdu do cross table), tak se zeptám. Co je špatného na tomto?
$zvire[$row['id_chovu']][$row['skupina']] = $row
//myslím, že při ukládání do DB lze zajistit, že potomek bude mít vždy větší id, takže stačí pole seřadit dle druhé indexu(0.1.5.9)

//Nebo by se to řadit nemusel a šlo by tyto 4 úrovně pro každé zvíře projít popořadě.
$x=0
for($i=0; $i<count($zvire['id_chovu']); $++) {
   echo $zvire['id_chovu'][$x];
   $x = zvire['id_chovu'][$x][$row['id_zvirete']];
}
Jcas
Profil *
Tak jsem se rozhodl.
Strom bude jen v jedné tabulce a pouze 2 úrovně. Parent-child.
Taky jsem si udělal obrázek. :)))))
pdf


[#5] Alphard
Poslední je asi věc, že bych tedy měl přiřadit nějaké indexy. To si nejsem zcela jistý jak. A ještě na jednu věc jsem nenašel odpověď
V článku o indexech má na konci při vytváření tabulky slovo REFERENCES. Nemůžu nic najít na vysvětlení.
Předpokládám, že to bude info o spojitosti bez závaznosti, jako má FOREIGN KEY.
Ale všude nacházím pouze vazbu FOREIGN KEY .... REFERENCES.
juriad
Profil
Podle standardu je:
CREATE TABLE this (
  col INT REFERENCES that (that_col)
);
stejné jako
CREATE TABLE this (
  col INT,
  FOREIGN KEY (col) REFERENCES that (that_col)
);

Druhý způsob je univerzálnější, protože může definovat více sloupcový cizí klíč:
CREATE TABLE this (
  col1 INT,
  col2 INT,
  FOREIGN KEY (col1, col2) REFERENCES that (that_col1, that_col2)
);

Ale, jak jsem našel v dokumentaci (předtím jsem to nevěděl), MySQL první způsob ignoruje:
MySQL does not recognize or support “inline REFERENCES specifications” (as defined in the SQL standard) where the references are defined as part of the column specification. MySQL accepts REFERENCES clauses only when specified as part of a separate FOREIGN KEY specification.
Kcko
Profil
Jcas:
Pokud se chceš podívat na poměrně jednoduchý kod, který dělá to co jsi popsal v začátcích tak http://sandbox.rjwebdesign.cz/dbmenu/pg.php

zdroják: http://sandbox.rjwebdesign.cz/dbmenu/source.phps (brát trošku s rezervou )

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

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