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 120 (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