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: MySQL Rekurze

Aktivity
Avatar
alfonz
Člen
Avatar
alfonz:22.8.2015 23:49

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
lmao
Avatar
Odpovídá na alfonz
Patrik Valkovič:23.8.2015 1:11

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ý
Tvůrce
Avatar
Odpovídá na alfonz
Jan Vargovský:23.8.2015 1:15

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 Hartinger
Vlastník
Avatar
Odpovídá na alfonz
David Hartinger:23.8.2015 10:21

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
You are the greatest project you will ever work on.
Avatar
alfonz
Člen
Avatar
Odpovídá na David Hartinger
alfonz:23.8.2015 11:23

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
lmao
Avatar
David Hartinger
Vlastník
Avatar
Odpovídá na alfonz
David Hartinger:23.8.2015 11:30

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

Nahoru Odpovědět
23.8.2015 11:30
You are the greatest project you will ever work on.
Avatar
Nahoru Odpovědět
23.8.2015 11:33
obsah kocky = r^2 ... a preto vlak drnká
Avatar
Odpovídá na alfonz
Patrik Valkovič:23.8.2015 12:35

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
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.