sql >> Databáze >  >> RDS >> Mysql

Který hierarchický model bych měl použít? Sousedství, vnořené nebo výčtové?

Obvykle existují tři druhy dotazů v hierarchiích, které způsobují potíže:

  1. Vraťte všechny předky
  2. Vrátit všechny potomky
  3. Vrátit všechny potomky (bezprostřední potomci).

Zde je malá tabulka, která ukazuje výkon různých metod v MySQL :

                        Ancestors  Descendants  Children        Maintainability InnoDB
Adjacency list          Good       Decent       Excellent       Easy            Yes
Nested sets (classic)   Poor       Excellent    Poor/Excellent  Very hard       Yes
Nested sets (spatial)   Excellent  Very good    Poor/Excellent  Very hard       No
Materialized path       Excellent  Very good    Poor/Excellent  Hard            Yes

V children , poor/excellent znamená, že odpověď závisí na tom, zda mícháte metodu se seznamem sousedství, tj. E. uložení parentID v každém záznamu.

Pro svůj úkol potřebujete všechny tři dotazy:

  1. Všichni předkové ukázat věc Země / Spojeného království / Devonu
  2. Všem dětem se zobrazí „Destinace v Evropě“ (položky)
  3. Všichni potomci pro zobrazení "Destinace v Evropě" (počet)

Šel bych po zhmotnělých cestách, protože tento druh hierarchie se mění jen zřídka (pouze v případě války, povstání atd.).

Vytvořte sloupec varchar s názvem path , indexujte jej a naplňte jej hodnotou takto:

1:234:6345:45454:

kde čísla jsou primární klíče příslušných rodičů ve správném pořadí (1 pro Evropu, 234 pro Velkou Británii atd.)

Budete také potřebovat tabulku nazvanou levels zachovat čísla od 1 až 20 (nebo jakoukoli maximální úroveň vnoření, kterou chcete).

Chcete-li vybrat všechny předky:

SELECT   pa.*
FROM     places p
JOIN     levels l
ON       SUBSTRING_INDEX(p.path, ':', l.level) <> p.path
JOIN     places pa
ON       pa.path = CONCAT(SUBSTRING_INDEX(p.path, ':', l.level), ':') 
WHERE    p.id = @id_of_place_in_devon

Chcete-li vybrat všechny děti a počty míst v nich:

SELECT  pc.*, COUNT(pp.id)
FROM    places p
JOIN    places pc
ON      pc.parentId = p.id
JOIN    places pp
ON      pp.path BETWEEN pc.path AND CONCAT(pc.path, ':')
        AND pp.id NOT IN
        (
        SELECT  parentId
        FROM    places
        )
WHERE   p.id = @id_of_europe
GROUP BY
        pc.id


  1. Jak zkrátit tabulku pomocí Doctrine 2?

  2. Jak make_interval() funguje v PostgreSQL

  3. Připojení MySQL přes localhost nefunguje, ale 127.0.0.1 funguje

  4. Oracle :jak odečíst dvě data a získat minuty výsledku