Mysql
 sql >> база данни >  >> RDS >> Mysql

Как да изберете подкатегории от избрана категория с помощта на вложена функция в PHP?

Има няколко решения. На първо място, ще използвам следните данни (categories таблица) като пример.

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

Решение 1 (Списък на съседство ):

Можете лесно да извлечете всички категории или подкатегории на категория в една заявка, като използвате WITH (Общи таблични изрази) клауза (изисква 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();
}

Ако използвате MySQL 5.7, променете тази функция по следния начин:

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

За да получите всички категории във вашата база данни:

$allCategories = getCategories($pdo);

Изход:

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

За да получите подкатегории на категория:

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

Изход:

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

Ако искате HTML изход, можете да преминете през $allCategories / $subCategories (въз основа на вашия пример):

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

Изход:

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

Изход:

Решение 2 (Вложени набори ):

Ще добавим допълнителни колони left и right към нашата таблица и поставете в нея числа, които ще идентифицират групите, принадлежащи на родителя. (Обърнете внимание, че няма да използваме parent_id колона.)

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

Сега трябва да променим нашата функция:

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

За да получите всички категории във вашата база данни:

$allCategories = getCategories($pdo);

Изход:

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

За да получите подкатегории на категория:

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

Изход:

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

Можете да изобразите HTML, както е показано в Решение 1 . Прочетете повече относно актуализирането и вмъкването на нови данни в модел на вложен набор.

Източници и четива:




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. MySQL C# асинхронните методи не работят?

  2. Как да импортирате SQL файл с помощта на mysqldump на Windows през командния ред

  3. MySQL твърде дълга настройка за съкращаване/грешка на varchar

  4. PHP/mysql получава броя на засегнатите редове на израза UPDATE

  5. Запитване на низ от колона int?