Der er et par løsninger. Først og fremmest vil jeg bruge følgende data (kategorier
tabel) som et eksempel.
+----+--------------------------------+---------- +| id | navn | parent_id |+----+--------------------------------+----------+| 1 | Elektronik | NULL || 2 | Beklædning og tøj | NULL || 3 | Telefoner og tilbehør | 1 || 4 | Computer og kontor | 1 || 5 | Herretøj | 2 || 6 | Dametøj | 2 || 7 | Mobiltelefoner | 3 || 8 | Mobiltelefon tilbehør | 3 || 9 | Telefondele | 3 || 10 | Computere og tilbehør | 4 || 11 | Tabletter og tilbehør | 4 || 12 | Computerudstyr | 4 || 13 | Computerkomponenter | 4 || 14 | Kontorelektronik | 4 |+----+-----------------------------+--------+ Løsning 1 (Adjacency List
):
Du kan nemt hente enten alle kategorier eller underkategorier af en kategori i en enkelt forespørgsel ved hjælp af Med (almindelige tabeludtryk)
klausul (kræver MySQL 8.0):
// Databaseforbindelse$options =[ PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => falsk, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,];$pdo =ny PDO('mysql:host=localhost;dbname=', '', '', $options);
funktion getCategories(PDO $db, $parentId =null){ $sql =$parentId ? 'MED RECURSIVE cte (id, name, parent_id) AS (SELECT id, name, parent_id FROM categories WHERE parent_id =? UNION ALLE VÆLG c.id, c.name, c.parent_id FRA kategorier c INNER JOIN cte ON c.parent_id =cte.id) SELECT * FROM cte' :'SELECT * FROM kategorier'; $stmt =$db->prepare($sql); $stmt->execute($parentId? [$parentId]:null); returner $stmt->fetchAll();}
Hvis du bruger MySQL 5.7, skal du ændre denne funktion sådan:
funktion getCategories(PDO $db, $parentId =null){ $sql =$parentId ? 'SELECT id, name, parent_id FROM (SELECT * FROM categories ORDER BY parent_id, id) c, (vælg @pv :=?) initialisering WHERE find_in_set(parent_id, @pv) AND LENGTH(@pv :=concat(@pv, ",", id))' :'VÆLG * FRA kategorier'; $stmt =$db->prepare($sql); $stmt->execute($parentId? [$parentId]:null); returner $stmt->fetchAll();}
For at få alle kategorier i din database:
$allCategories =getCategories($pdo);
Output:
+----+--------------------------------+---------- +| id | navn | parent_id |+----+--------------------------------+----------+| 1 | Elektronik | NULL || 2 | Beklædning og tøj | NULL || 3 | Telefoner og tilbehør | 1 || 4 | Computer og kontor | 1 || 5 | Herretøj | 2 || 6 | Dametøj | 2 || 7 | Mobiltelefoner | 3 || 8 | Mobiltelefontilbehør | 3 || 9 | Telefondele | 3 || 10 | Computere og tilbehør | 4 || 11 | Tabletter og tilbehør | 4 || 12 | Computerudstyr | 4 || 13 | Computerkomponenter | 4 || 14 | Kontorelektronik | 4 |+----+-----------------------------+--------+
Sådan får du underkategorier til en kategori:
$subCategories =getCategories($pdo, 1); // 1 er parent_id
Output:
+----+--------------------------------+---------- +| id | navn | parent_id |+----+--------------------------------+----------+| 3 | Telefoner og tilbehør | 1 || 4 | Computer og kontor | 1 || 7 | Mobiltelefoner | 3 || 8 | Mobiltelefontilbehør | 3 || 9 | Telefondele | 3 || 10 | Computere og tilbehør | 4 || 11 | Tabletter og tilbehør | 4 || 12 | Computerudstyr | 4 || 13 | Computerkomponenter | 4 || 14 | Kontorelektronik | 4 |+----+-----------------------------+--------+
Hvis du vil have et HTML-output, kan du gå gennem $allCategories
/ $subCategories
(baseret på dit eksempel):
funktion prepareCategories(array $categories){ $result =[ 'all_categories' => [], 'parent_categories' => [] ]; foreach ($categories as $category) { $result['all_categories'][$category['id']] =$category; $result['parent_categories'][$category['parent_id']][] =$category['id']; } returner $result;}funktion buildCategories($categories, $parentId =null){ if (!isset($categories['parent_categories'][$parentId])) { return ''; } $html =''; foreach ($categories['parent_categories'][$parentId] as $cat_id) { if (isset($categories['parent_categories'][$cat_id])) { $html .="- {$categories['all_categories'][$cat_id]['name']}
"; $html .=buildCategories($categories, $cat_id); $html .='
'; } else { $html .="- {$categories['all_categories'][$cat_id]['name']}
"; } } $html .='
'; returner $html;}
echo buildCategories(prepareCategories($allCategories));
Output:
echo buildCategories(prepareCategories($subCategories), 1);
Output:
Løsning 2 (Indlejrede sæt
):
Vi tilføjer yderligere kolonner til venstre
og right
til vores tabel og læg tal i den, som vil identificere de grupper, der tilhører forælderen. (Bemærk, at vi ikke bruger parent_id
kolonne.)
+----+--------------------------------+---------- ---------------+| id | navn | forældre_id | venstre | højre |+----+----------------------------+-------------------- -----------+| 1 | Elektronik | NULL | 1 | 22 || 2 | Beklædning og tøj | NULL | 23 | 28 || 3 | Telefoner og tilbehør | 1 | 2 | 9 || 4 | Computer og kontor | 1 | 10 | 21 || 5 | Herretøj | 2 | 24 | 25 || 6 | Dametøj | 2 | 26 | 27 || 7 | Mobiltelefoner | 3 | 3 | 4 || 8 | Mobiltelefontilbehør | 3 | 5 | 6 || 9 | Telefondele | 3 | 7 | 8 || 10 | Computere og tilbehør | 4 | 11 | 12 || 11 | Tabletter og tilbehør | 4 | 13 | 14 || 12 | Computerudstyr | 4 | 15 | 16 || 13 | Computerkomponenter | 4 | 17 | 18 || 14 | Kontorelektronik | 4 | 19 | 20 |+----+----------------------------+-------- -----------+
Nu skal vi ændre vores funktion:
funktion getCategories(PDO $db, $parentId =null){ $sql =$parentId ? 'VÆLG børn.* FRA kategorier forælder INNER JOIN-kategorier børn PÅ parent.left children.left WHERE parent.id =?' :'VÆLG * FRA kategorier'; $stmt =$db->prepare($sql); $stmt->execute($parentId? [$parentId]:null); returner $stmt->fetchAll();}
For at få alle kategorier i din database:
$allCategories =getCategories($pdo);
Output:
+----+--------------------------------+---------- ---------------+| id | navn | forældre_id | venstre | højre |+----+----------------------------+-------------------- -----------+| 1 | Elektronik | NULL | 1 | 22 || 2 | Beklædning og tøj | NULL | 23 | 28 || 3 | Telefoner og tilbehør | 1 | 2 | 9 || 4 | Computer og kontor | 1 | 10 | 21 || 5 | Herretøj | 2 | 24 | 25 || 6 | Dametøj | 2 | 26 | 27 || 7 | Mobiltelefoner | 3 | 3 | 4 || 8 | Mobiltelefontilbehør | 3 | 5 | 6 || 9 | Telefondele | 3 | 7 | 8 || 10 | Computere og tilbehør | 4 | 11 | 12 || 11 | Tabletter og tilbehør | 4 | 13 | 14 || 12 | Computerudstyr | 4 | 15 | 16 || 13 | Computerkomponenter | 4 | 17 | 18 || 14 | Kontorelektronik | 4 | 19 | 20 |+----+----------------------------+-------- -----------+
Sådan får du underkategorier til en kategori:
$subCategories =getCategories($pdo, 1); // 1 er parent_id
Output:
+----+--------------------------------+---------- ---------------+| id | navn | forældre_id | venstre | højre |+----+----------------------------+-------------------- -----------+| 3 | Telefoner og tilbehør | 1 | 2 | 9 || 4 | Computer og kontor | 1 | 10 | 21 || 7 | Mobiltelefoner | 3 | 3 | 4 || 8 | Mobiltelefontilbehør | 3 | 5 | 6 || 9 | Telefondele | 3 | 7 | 8 || 10 | Computere og tilbehør | 4 | 11 | 12 || 11 | Tabletter og tilbehør | 4 | 13 | 14 || 12 | Computerudstyr | 4 | 15 | 16 || 13 | Computerkomponenter | 4 | 17 | 18 || 14 | Kontorelektronik | 4 | 19 | 20 |+----+----------------------------+-------- -----------+
Du kan gengive HTML som vist i Løsning 1 . Læs mere
om opdatering og indsættelse af nye data i indlejret sætmodel.
Kilder og læsninger:
- Administration af hierarkiske data i MySQL - indlejret sæt
- Håndtering af hierarkiske data i MySQL
- Modeller til hierarkiske data
- Håndtering af hierarkiske data i MySQL ved hjælp af Adjacency List Model
- Adjacency liste vs. indlejrede sæt:MySQL
- One flere indlejrede intervaller vs. tilstødende liste sammenligning