sql >> Database >  >> RDS >> Mysql

Hoe subcategorieën uit de geselecteerde categorie selecteren met behulp van een geneste functie in PHP?

Er zijn een aantal oplossingen. Allereerst gebruik ik de volgende gegevens (categories tabel) als voorbeeld.

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

Oplossing 1 (Aangrenzende lijst ):

U kunt eenvoudig alle categorieën of subcategorieën van een categorie ophalen in een enkele zoekopdracht met MET (algemene tabeluitdrukkingen) clausule (vereist 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();
}

Als je MySQL 5.7 gebruikt, verander die functie dan als volgt:

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();
}

Om alle categorieën in uw database te krijgen:

$allCategories = getCategories($pdo);

Uitgang:

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

Om subcategorieën van een categorie te krijgen:

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

Uitgang:

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

Als u een HTML-uitvoer wilt, kunt u door $allCategories lopen / $subCategories (gebaseerd op uw voorbeeld):

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));

Uitgang:

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

Uitgang:

Oplossing 2 (Geneste sets ):

We zullen extra kolommen toevoegen left en right naar onze tabel en zet er nummers in die de groepen identificeren die bij de ouder horen. (Houd er rekening mee dat we parent_id niet zullen gebruiken kolom.)

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

Nu moeten we onze functie wijzigen:

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();
}

Om alle categorieën in uw database te krijgen:

$allCategories = getCategories($pdo);

Uitgang:

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

Om subcategorieën van een categorie te krijgen:

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

Uitgang:

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

U kunt HTML weergeven zoals weergegeven in Oplossing 1 . Meer lezen over het bijwerken en invoegen van nieuwe gegevens in het geneste setmodel.

Bronnen en gelezen:




  1. Hoe de voortgang van het uploaden van .csv in MySQL te zien

  2. SQL Server 2016:een opgeslagen procedure maken

  3. MySQL's INSERT IGNORE INTO &buitenlandse sleutels

  4. Gegevensbestanden verplaatsen in SQL Server - Deel 1