Как оптимально получить материнские элементы из базы?

Ссылка скопирована
30 января 2026 1 ответ

Например есть таблица
id
pid
name

есть оптимальный способ получить все элементы одной ветки, одним sql запросом?
например для Breadcrumb
В голову приходит одно решение запросить все элементы и записать $arr[pid]

Дополнительно:

Из вопроса непонятные, что вы понимаете под всеми элементами одной ветки. Приведите пример.

  • Фрагменты кода надо размещать в виде текста и оборачивать тэгом code для корректного отображения. Удобно делать кнопкой </>
    Это обязательно, см.п.3.8 Регламента.
    Сюда же относится traceback, ввод и вывод в консоли и другая структурированная текстовая инфа.
  • Алан Гибизов, например

    категория 1 / категория 5 / категория 7 / категория 20
    категория 2 / категория 20 / категория 45
    категория 46 / категория 70 / категория 80 / категория 99

    Мы находится на странице (категория 80) нужно получить id (категория 46 / категория 70)
    можно сделать sql запрос, чтобы получить нужные id, а не получать все категории, а потом вытаскивать из массива нужные id

  • Дмитрий Котеров когда-то опубликовал библиотеку, которая генерировала SQL-запрос с джойнами . Ограничение было такое: надо было заранее знать верхний предел уровней вложенности. На выходе таблица со столбцами t1.id, t1.pid, t1.name, t2.id, t2.pid, t2.name ...
    Жаль, форум "Лаборатории" давно не работает.
  • Ответы:

    Не указано, что за сервер SQL используется. Вот, например, для MySQL 8:

    WITH RECURSIVE `cte` AS (   SELECT `id`, `pid`, `name`, 0 AS `level`     FROM `table`   UNION SELECT `p`.`id`, `p`.`pid`, `p`,`name`, `cte`.`level` + 1 AS `level`     FROM `cte`      JOIN `table` AS `p` ON `p`.`id` = `cte`.`pid` ) SELECT `id`, `name`, `level`   FROM `cte`   ORDER BY `level`

    WITH RECURSIVE `cte` AS ( SELECT `id`, `pid`, `name`, 0 AS `level` FROM `table` UNION SELECT `p`.`id`, `p`.`pid`, `p`,`name`, `cte`.`level` + 1 AS `level` FROM `cte` JOIN `table` AS `p` ON `p`.`id` = `cte`.`pid` ) SELECT `id`, `name`, `level` FROM `cte` ORDER BY `level`

    • Решение интересное, мне кажется, это ресурсозатратно. Спасибо! буду пробовать
    • Элдор Суванов, Несколько запросов будут гораздо затратнее.
    • Элдор Суванов,

      мне кажется, это ресурсозатратно.

      Только если у вас миллионы категорий, на значениях порядка нескольких тысяч категорий это пыль...

    На php можно так попробовать, но тут не один запрос

    $query = "SELECT id, pid, name FROM your_table"; $result = $mysqli-&gt;query($query);  $items = []; while($row = $result-&gt;fetch_assoc()){     $items[$row['id']] = ['pid' =&gt; $row['pid'], 'name' =&gt; $row['name']]; }  function buildTree(array $elements, $parentId = 0) {     $branch = array();      foreach ($elements as $element) {         if ($element['pid'] == $parentId) {             $children = buildTree($elements, $element['id']);             if ($children) {                 $element['children'] = $children;             }             $branch[] = $element;         }     }      return $branch; }  $tree = buildTree($items);

    $query = "SELECT id, pid, name FROM your_table"; $result = $mysqli-&gt;query($query); $items = []; while($row = $result-&gt;fetch_assoc()){ $items[$row['id']] = ['pid' =&gt; $row['pid'], 'name' =&gt; $row['name']]; } function buildTree(array $elements, $parentId = 0) { $branch = array(); foreach ($elements as $element) { if ($element['pid'] == $parentId) { $children = buildTree($elements, $element['id']); if ($children) { $element['children'] = $children; } $branch[] = $element; } } return $branch; } $tree = buildTree($items);

    • function pids($sql, $sid)  	{ 		$sql = json_decode(json_encode($sql), true); 		$index = $sid; 		$arr = []; 	 		foreach ($sql as $n) 		foreach ($sql as $item) 		{ 			list($id, $pid) = array_values($item); 			if ($id == $index) 			{ 				$index = $pid; 				$arr[] = $item; 			} 		} 		return $arr; 	}  $breadcrumb[] = ['name' =&gt; 'Главная', 'href' =&gt; '/']; $breadcrumb[] = ['name' =&gt; 'Категории', 'href' =&gt; route('admin.categories')]; $categories = DB::table('categories') -&gt; select('id') -&gt; addSelect('categories_id') -&gt; addSelect('categories_name') -&gt; get(); $tmp = array_reverse(pids($categories, intval($product -&gt; categories_id))); foreach ($tmp as $item) $breadcrumb[] = ['name' =&gt; $item['categories_name'], 'href' =&gt; route('admin.categories.list', ['id' =&gt; $item['id']])];

      function pids($sql, $sid) { $sql = json_decode(json_encode($sql), true); $index = $sid; $arr = []; foreach ($sql as $n) foreach ($sql as $item) { list($id, $pid) = array_values($item); if ($id == $index) { $index = $pid; $arr[] = $item; } } return $arr; } $breadcrumb[] = ['name' =&gt; 'Главная', 'href' =&gt; '/']; $breadcrumb[] = ['name' =&gt; 'Категории', 'href' =&gt; route('admin.categories')]; $categories = DB::table('categories') -&gt; select('id') -&gt; addSelect('categories_id') -&gt; addSelect('categories_name') -&gt; get(); $tmp = array_reverse(pids($categories, intval($product -&gt; categories_id))); foreach ($tmp as $item) $breadcrumb[] = ['name' =&gt; $item['categories_name'], 'href' =&gt; route('admin.categories.list', ['id' =&gt; $item['id']])];

      Я реализовал проше, просто хочу найти решение где не придется, получать всю таблицу из базы и не делать лишние итерации или это не нужная оптимизация?

    • Элдор Суванов, Можно попробовать сделать через with recursive в базе прям

    Элдор Суванов, почитайте статью. Там рассмотрены основные варианты структур, реализующих решение вашей проблемы, соответствуюзих им классов и соответствующих атрибутам этих классов запросов sql.
    spoilerВы должны были сначала поискать, потом сюда писать вопрос. Публиковать вопросы, ответ на которые легко найти поиском в интернете, запрещено (п.2.2 Регламента). Я, к примеру, нашел за 5 секунд по запросу «sql цепочка родителей»

    • ORM Hibernate, это библиотека для java. Конечно же я сюда пришел с последнюю очередь, в рунете не нашел оптимального решения.
    • Элдор Суванов, да при чем тут ORM? Вы статью прочтите. ORM там существенной роли не играет - основная суть как раз между строк про ORM. Разобраны основные способы хранения деревьев в БД, ваш способ, как я понял, там первый. И разобраны запросы SQL для основных действий с этой структурой - получения предков, потомков, изменения и удаления. То, что оно привязано к конкретной ORM, вообще дело десятое.

      Впрочем, вам тут уже накидали более-менее готовых образцов…

    Нужно решить такую задачу?

    Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.

    Заказать помощь
    Лучший ответ
    1
    Роман IT Ответ

    Для оптимального получения материнских элементов из базы данных, вам следует использовать запрос SQL, который будет эффективно выбирать необходимые данные. Вот пример того, как можно это сделать на языке PHP с использованием MySQL:

    // Подключение к базе данных
    $conn = new mysqli($servername, $username, $password, $dbname);
     
    // Проверка соединения
    if ($conn-&gt;connect_error) {
        die("Connection failed: " . $conn-&gt;connect_error);
    }
     
    // Запрос к базе данных для выборки материнских элементов
    $sql = "SELECT * FROM your_table WHERE parent_id IS NULL";
     
    $result = $conn-&gt;query($sql);
     
    if ($result-&gt;num_rows &gt; 0) {
        // Вывод данных материнских элементов
        while($row = $result-&gt;fetch_assoc()) {
            echo "ID: " . $row["id"]. " - Name: " . $row["name"]. "<br>";
        }
    } else {
        echo "0 results";
    }
     
    $conn-&gt;close();

    // Подключение к базе данных $conn = new mysqli($servername, $username, $password, $dbname); // Проверка соединения if ($conn-&gt;connect_error) { die("Connection failed: " . $conn-&gt;connect_error); } // Запрос к базе данных для выборки материнских элементов $sql = "SELECT * FROM your_table WHERE parent_id IS NULL"; $result = $conn-&gt;query($sql); if ($result-&gt;num_rows &gt; 0) { // Вывод данных материнских элементов while($row = $result-&gt;fetch_assoc()) { echo "ID: " . $row["id"]. " - Name: " . $row["name"]. "<br>"; } } else { echo "0 results"; } $conn-&gt;close();

    В данном примере мы используем запрос SQL SELECT для выборки всех элементов из таблицы, у которых поле parent_id равно NULL. Это позволяет нам выбрать только материнские элементы. Затем мы выводим полученные данные на экран.

    Не забудьте заменить "your_table", "parent_id", "id" и "name" на соответствующие названия таблицы и полей в вашей базе данных. Также убедитесь, что у вас есть соединение с базой данных и оно корректно настроено.

    Этот подход поможет вам эффективно получить материнские элементы из базы данных и использовать их в вашем приложении.

    Другие ответы (0)

    Пока нет других ответов. Будьте первым, кто поможет автору.

    Ответить на вопрос

    комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *

    Вам также может быть интересно