Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Wie wählt man Unterkategorien aus der ausgewählten Kategorie mit einer verschachtelten Funktion in PHP aus?

Es gibt ein paar Lösungen. Zunächst verwende ich die folgenden Daten (categories Tabelle) als Beispiel.

+----+--------------------------+-----------+
| id | name                     | parent_id |
+----+--------------------------+-----------+
|  1 | Electronics              |      NULL |
|  2 | Apparel & Clothing       |      NULL |
|  3 | Phones & Accessories     |         1 |
|  4 | Computer & Office        |         1 |
|  5 | Men's Clothing           |         2 |
|  6 | Women's Clothing         |         2 |
|  7 | Cell Phones              |         3 |
|  8 | Cell Phone Accessories   |         3 |
|  9 | Phone Parts              |         3 |
| 10 | Computers & Accessories  |         4 |
| 11 | Tablets & Accessories    |         4 |
| 12 | Computer Peripherals     |         4 |
| 13 | Computer Components      |         4 |
| 14 | Office Electronics       |         4 |
+----+--------------------------+-----------+

Lösung 1 (Adjazenzliste ). ):

Sie können entweder alle Kategorien oder Unterkategorien einer Kategorie in einer einzigen Abfrage mit WITH (Allgemeine Tabellenausdrücke) -Klausel (erfordert MySQL 8.0):

// Database connection

$options = [
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES => false,
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
];

$pdo = new PDO('mysql:host=localhost;dbname=<DATABASE_NAME>', '<USERNAME>', '<PASSWORD>', $options);
function getCategories(PDO $db, $parentId = null)
{
    $sql = $parentId ? 'WITH RECURSIVE cte (id, name, parent_id) AS (SELECT id, name, parent_id FROM categories WHERE parent_id = ? UNION ALL SELECT c.id, c.name, c.parent_id FROM categories c INNER JOIN cte ON c.parent_id = cte.id) SELECT * FROM cte' : 'SELECT * FROM categories';
    $stmt = $db->prepare($sql);
    $stmt->execute($parentId ? [$parentId] : null);
    return $stmt->fetchAll();
}

Wenn Sie MySQL 5.7 verwenden, ändern Sie diese Funktion wie folgt:

function getCategories(PDO $db, $parentId = null)
{
    $sql = $parentId ? 'SELECT id, name, parent_id FROM (SELECT * FROM categories ORDER BY parent_id, id) c, (select @pv := ?) initialisation WHERE find_in_set(parent_id, @pv) AND LENGTH(@pv := concat(@pv, ",", id))' : 'SELECT * FROM categories';
    $stmt = $db->prepare($sql);
    $stmt->execute($parentId ? [$parentId] : null);
    return $stmt->fetchAll();
}

So erhalten Sie alle Kategorien in Ihrer Datenbank:

$allCategories = getCategories($pdo);

Ausgabe:

+----+--------------------------+-----------+
| id | name                     | parent_id |
+----+--------------------------+-----------+
|  1 | Electronics              |      NULL |
|  2 | Apparel & Clothing       |      NULL |
|  3 | Phones & Accessories     |         1 |
|  4 | Computer & Office        |         1 |
|  5 | Men's Clothing           |         2 |
|  6 | Women's Clothing         |         2 |
|  7 | Cell Phones              |         3 |
|  8 | Cell Phone Accessories   |         3 |
|  9 | Phone Parts              |         3 |
| 10 | Computers & Accessories  |         4 |
| 11 | Tablets & Accessories    |         4 |
| 12 | Computer Peripherals     |         4 |
| 13 | Computer Components      |         4 |
| 14 | Office Electronics       |         4 |
+----+--------------------------+-----------+

So erhalten Sie Unterkategorien einer Kategorie:

$subCategories = getCategories($pdo, 1); // 1 is parent_id

Ausgabe:

+----+--------------------------+-----------+
| id | name                     | parent_id |
+----+--------------------------+-----------+
|  3 | Phones & Accessories     |         1 |
|  4 | Computer & Office        |         1 |
|  7 | Cell Phones              |         3 |
|  8 | Cell Phone Accessories   |         3 |
|  9 | Phone Parts              |         3 |
| 10 | Computers & Accessories  |         4 |
| 11 | Tablets & Accessories    |         4 |
| 12 | Computer Peripherals     |         4 |
| 13 | Computer Components      |         4 |
| 14 | Office Electronics       |         4 |
+----+--------------------------+-----------+

Wenn Sie eine HTML-Ausgabe wünschen, können Sie $allCategories durchlaufen / $subCategories (basierend auf Ihrem Beispiel):

function 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'];
    }
    return $result;
}

function buildCategories($categories, $parentId = null)
{
    if (!isset($categories['parent_categories'][$parentId])) {
        return '';
    }

    $html = '<ul>';
    foreach ($categories['parent_categories'][$parentId] as $cat_id) {
        if (isset($categories['parent_categories'][$cat_id])) {
            $html .= "<li><a href='#'>{$categories['all_categories'][$cat_id]['name']}</a>";
            $html .= buildCategories($categories, $cat_id);
            $html .= '</li>';
        } else {
            $html .= "<li><a href='#'>{$categories['all_categories'][$cat_id]['name']}</a></li>";
        }
    }
    $html .= '</ul>';

    return $html;
}
echo buildCategories(prepareCategories($allCategories));

Ausgabe:

echo buildCategories(prepareCategories($subCategories), 1);

Ausgabe:

Lösung 2 (Verschachtelte Mengen ). ):

Wir fügen zusätzliche Spalten left hinzu und right zu unserer Tabelle und tragen Sie Zahlen ein, die die Gruppen identifizieren, die dem Elternteil gehören. (Beachten Sie, dass wir parent_id nicht verwenden werden Spalte.)

+----+--------------------------+--------------------------+
| id | name                     | parent_id | left | right |
+----+--------------------------+--------------------------+
|  1 | Electronics              |      NULL |    1 |    22 |
|  2 | Apparel & Clothing       |      NULL |   23 |    28 |
|  3 | Phones & Accessories     |         1 |    2 |     9 |
|  4 | Computer & Office        |         1 |   10 |    21 |
|  5 | Men's Clothing           |         2 |   24 |    25 |
|  6 | Women's Clothing         |         2 |   26 |    27 |
|  7 | Cell Phones              |         3 |    3 |     4 |
|  8 | Cell Phone Accessories   |         3 |    5 |     6 |
|  9 | Phone Parts              |         3 |    7 |     8 |
| 10 | Computers & Accessories  |         4 |   11 |    12 |
| 11 | Tablets & Accessories    |         4 |   13 |    14 |
| 12 | Computer Peripherals     |         4 |   15 |    16 |
| 13 | Computer Components      |         4 |   17 |    18 |
| 14 | Office Electronics       |         4 |   19 |    20 |
+----+--------------------------+--------------------------+

Jetzt müssen wir unsere Funktion ändern:

function getCategories(PDO $db, $parentId = null)
{
    $sql = $parentId ? 'SELECT children.* FROM categories parent INNER JOIN categories children ON parent.left < children.left AND parent.right > children.left WHERE parent.id = ?' : 'SELECT * FROM categories';
    $stmt = $db->prepare($sql);
    $stmt->execute($parentId ? [$parentId] : null);
    return $stmt->fetchAll();
}

So erhalten Sie alle Kategorien in Ihrer Datenbank:

$allCategories = getCategories($pdo);

Ausgabe:

+----+--------------------------+--------------------------+
| id | name                     | parent_id | left | right |
+----+--------------------------+--------------------------+
|  1 | Electronics              |      NULL |    1 |    22 |
|  2 | Apparel & Clothing       |      NULL |   23 |    28 |
|  3 | Phones & Accessories     |         1 |    2 |     9 |
|  4 | Computer & Office        |         1 |   10 |    21 |
|  5 | Men's Clothing           |         2 |   24 |    25 |
|  6 | Women's Clothing         |         2 |   26 |    27 |
|  7 | Cell Phones              |         3 |    3 |     4 |
|  8 | Cell Phone Accessories   |         3 |    5 |     6 |
|  9 | Phone Parts              |         3 |    7 |     8 |
| 10 | Computers & Accessories  |         4 |   11 |    12 |
| 11 | Tablets & Accessories    |         4 |   13 |    14 |
| 12 | Computer Peripherals     |         4 |   15 |    16 |
| 13 | Computer Components      |         4 |   17 |    18 |
| 14 | Office Electronics       |         4 |   19 |    20 |
+----+--------------------------+--------------------------+

So erhalten Sie Unterkategorien einer Kategorie:

$subCategories = getCategories($pdo, 1); // 1 is parent_id

Ausgabe:

+----+--------------------------+--------------------------+
| id | name                     | parent_id | left | right |
+----+--------------------------+--------------------------+
|  3 | Phones & Accessories     |         1 |    2 |     9 |
|  4 | Computer & Office        |         1 |   10 |    21 |
|  7 | Cell Phones              |         3 |    3 |     4 |
|  8 | Cell Phone Accessories   |         3 |    5 |     6 |
|  9 | Phone Parts              |         3 |    7 |     8 |
| 10 | Computers & Accessories  |         4 |   11 |    12 |
| 11 | Tablets & Accessories    |         4 |   13 |    14 |
| 12 | Computer Peripherals     |         4 |   15 |    16 |
| 13 | Computer Components      |         4 |   17 |    18 |
| 14 | Office Electronics       |         4 |   19 |    20 |
+----+--------------------------+--------------------------+

Sie können HTML wie in Lösung 1 darstellen . Weitere Informationen Informationen zum Aktualisieren und Einfügen neuer Daten in ein verschachteltes Mengenmodell.

Quellen und Leseproben: