Diskuze: MySQL Rekurze

Ostatní jazyky SQL SQL a databáze MySQL Rekurze

Avatar
Denis Homolík (Alfonz):

Je možné možné nějak vytvořit uvnitř příkazu SELECT rekurzi? Konkrétně potřebuji vytvořit z tabulky url. Dostanu ID a mám projít tabulku až dokud Předek není NULL
Tabulka:

ID Předek Url
0 NULL /
1 0 clanky
2 1 podkategorie
3 0 obrazky
4 2 clanek
5 1 podkategorie

Takže když třeba dostanu ID 4, vrátí to toto:

ID Předek Url
4 2 clanek
2 1 podkategorie
1 0 kategorie
0 NULL /

Začne na 4, ta ukazuje na 2, ta ukazuje na 1, ta ukazuje na 0 a 0 ukazuje na NULL. Jelikož nevím hloubku, připadá mi nejlepší použití rekurze.

Takže z toho pak můžu poskládat:

/kategorie/podkategorie/clanek

Samozřejmě bych to mohl udělat v PHP, ale chci vědět jestli to jde a nemusel bych tolik zatěžovat db.

Odpovědět 22.8.2015 23:49
Vše je možné, dokud si to myslíte!
Avatar
patrik.valkovic
Šéfredaktor
Avatar
Odpovídá na Denis Homolík (Alfonz)
patrik.valkovic:

Samozřejmě, že to je možné. Podívej se na T-SQL. Vytvoříš si proměnnou, ve které budeš mít předka a dokud nebude null, tak pokračuješ v cyklu dále. Při troše snahy ti databáze vyplivne záznamy seřazené tak, jak na sebe navazují.

Nahoru Odpovědět 23.8.2015 1:11
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
Avatar
Jan Vargovský
Redaktor
Avatar
Odpovídá na Denis Homolík (Alfonz)
Jan Vargovský:

Zkus pohledat něco ve smyslu "mysql create tree structure query". Něco jsem našel, ale já moc do sql nevidím, ani nemám momentálně možnost to testnout.

 
Nahoru Odpovědět 23.8.2015 1:15
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Denis Homolík (Alfonz)
David Čápka:

V DB to uděláš těžko nebo zbytečně komplikovaně a ničemu si oproti PHP nepomůžeš. Jsou tu na to články, třeba tady: http://www.itnetwork.cz/…tabaze-v-php

Nahoru Odpovědět 23.8.2015 10:21
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
Odpovídá na David Čápka
Denis Homolík (Alfonz):

Udělat to v PHP samozřejmě není problém, ale nechce se mi zatěžovat databázi několika dotazy.
Moje metoda v PHP:

public function createLink($id, $link)
{
        $data = $this->findOne("SELECT * FROM page WHERE id=:id", ["id" => $id]);
        //Pokud existuje,pokračuje v rekurzi jinak začne vracet
        if($data)
        {
                //Přidá aktuální prvek k linku
                $link = "/" . $data["url"] . $link;
                //Získá postupně vracející se link
                $return = $this->createLink($data["section"], $link);
        }
        else
        {
                //Vrátí hodnotu linku
                return $link;
        }
        //Vrátí hodnotu linku
        return $return;
}
Nahoru Odpovědět 23.8.2015 11:23
Vše je možné, dokud si to myslíte!
Avatar
David Čápka
Tým ITnetwork
Avatar
Odpovídá na Denis Homolík (Alfonz)
David Čápka:

Stačí ti jeden dotaz, poslal jsem ti řešení si to přečti.

Nahoru Odpovědět 23.8.2015 11:30
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
Matúš Petrofčík
Šéfredaktor
Avatar
Nahoru Odpovědět 23.8.2015 11:33
obsah kocky = r^2 ... a preto vlak drnká
Avatar
patrik.valkovic
Šéfredaktor
Avatar
Odpovídá na Denis Homolík (Alfonz)
patrik.valkovic:

Nevidím důvod, proč by měla databáze posílat zbytečně tolik dat. Kromě režie, potřebné na přenesení takového množství, vzniká i bezpečnostní riziko, protože skript dostane i informace, které mu nepatří (například informace o ostatních uživatelích nepotřebuje).
Já se řídím heslem, že by aplikace měla vždy získat přesně ty informace, které potřebuje, nic navíc, nic míň. A navíc v jendom dotazu.
Jak jsem psal, řešení je, chce to ale znát trošku víc než SELECT. Přikládám řešení (včera o půlnoci se mi vážně nechtělo :D)

Vytvoření tabulky:

DROP TABLE IF EXISTS testtable;
CREATE TABLE IF NOT EXISTS `testtable` (
  `Id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `Parent` int(11) DEFAULT NULL,
  `Url` text
) ENGINE=InnoDB CHARSET=UTF8;

INSERT INTO testtable(Parent,Url) VALUES
(NULL , "/"),
(1 ,"clanky"),
(2 ,"podkategorie"),
(1 ,"obrazky"),
(3 ,"clanek"),
(2 ,"podkategorie");

Vytvoření procedury, která bude data vybírat:

DROP PROCEDURE IF EXISTS CreateTempTable;
DELIMITER $
CREATE PROCEDURE CreateTempTable(IN Param INT) DETERMINISTIC
BEGIN
        DECLARE Actual INT;
    DECLARE TEMP INT;
    SELECT Param INTO Actual;
    DROP TABLE IF EXISTS MyTempTable;
    CREATE TEMPORARY TABLE MyTempTable(
                ID INT NOT NULL,
                Prevision INT,
                Url TEXT);
        WHILE Actual IS NOT NULL DO
                INSERT INTO MyTempTable SELECT * FROM testtable WHERE Id=Actual;
                SELECT Parent INTO TEMP FROM testtable WHERE Id=Actual;
        SELECT TEMP INTO Actual;
    END WHILE;
END$
DELIMITER ;

Dotaz je poté jednoduše

CALL CreateTempTable(5);
SELECT * FROM MyTempTable;

nic míň, a dostanu přesně data, které ptořebuji.

5 3 clanek
3 2 podkategorie
2 1 clanky
1 0 NULL

Používá se TEMPORARY tabulka, takže lze použít všechny příkazy pro třídění, řazení atd. Nejsem si moc jistý, jak to bude fungovat u více uživatelů, ale každá session by měla mít vlastní, takže by v tom problém být neměl.

Snad to na Tebe není moc složité :)

Nahoru Odpovědět  +1 23.8.2015 12:35
Nikdy neumíme dost na to, abychom se nemohli něco nového naučit.
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 8 zpráv z 8.