Создание неупорядоченного списка из нескольких таблиц MySQL

Я пытаюсь создать меню, заполненное категориями, подкатегориями и третичными категориями, которые хранятся в трех отдельных таблицах в базе данных следующим образом:

TABLE A
------------------------
| ID | name            |
| 1  | Category 1      |
| 2  | Category 2      |
------------------------

TABLE B
------------------------------------
| ID | Parent_ID | name_b          |
| 1  |     1     | Subcategory 1   |
| 2  |     1     | Subcategory 2   |
| 3  |     2     | Subcategory 3   |
------------------------------------

TABLE C
--------------------------------------
| ID | Parent_ID | name_c             |
| 1  |     1     | Tertiarycategory 1 |
| 2  |     2     | Tertiarycategory 2 |
| 3  |     2     | Tertiarycategory 3 |
| 4  |     3     | Tertiarycategory 4 |
--------------------------------------

Они должны быть возвращены в неупорядоченном списке, выглядящем как

  • Категория 1
    • Подкатегория 1
      • Третичная категория 1
    • Подкатегория 2
      • Третичная категория
      • Третичная категория 3
  • Категория 2
    • Подкатегория 3
      • Третичная категория 4

Я пару дней гуглял, пробуя разные вещи, но, похоже, не могу заставить их работать, поэтому очень буду признателен, если кто-то сможет взломать это для меня 🙂

Пробовал это, чтобы получить первый и второй уровни (без перечисления, просто нормальное эхо, пока я правильно понимаю запросы), но это не сработало вообще …

    $query_select = "SELECT * FROM table_a";
$result_select = mysqli_query($link, $query_select) or die(mysql_error());
$rows = array();
while($menurow = mysqli_fetch_array($result_select))
$menurows[] = $menurow;
foreach($menurows as $menurow){
$ename = stripslashes($menurow['name']);
$eid = $menurow['id'];
echo $ename . '<br/>';
$query_select2 = "SELECT * FROM table_b WHERE parent_id = '$eid'";
$result_select2 = mysqli_query($link, $query_select2) or die(mysql_error());
$rows2 = array();
while($menurow2 = mysqli_fetch_array($result_select2))
$menurows2[] = $menurow2;
foreach($menurows2 as $menurow2){
$ename2 = stripslashes($menurow2['name_b']);
$eid2 = $menurow2['id'];
echo $ename2 . '<br/>';

}

}

-1

Решение

Я бы просто использовал простое соединение, чтобы получить все родительские / дочерние отношения, и отсортировать вывод родителей верхнего уровня в коде, когда они меняются (это было бы легко в php).

SELECT name, name_b, name_c
FROM A
LEFT OUTER JOIN B
ON A.ID = B.Parent_ID
LEFT OUTER JOIN C
ON B.ID = C.Parent_ID
ORDER BY A.ID, B.ID, C.ID

РЕДАКТИРОВАТЬ

PHP скрипт для извлечения деталей из таблицы и построения неупорядоченных списков.

Это использует небольшой класс для вывода каждого неупорядоченного списка, закрывая его в деструкторе. Затем он создает экземпляр этого класса для каждого уровня неупорядоченного списка.

<?php

#------ database connections -------
define('MYSQLHOST','localhost');
define('MYSQLUSER','root');
define('MYSQLPASS','');
define('MYSQLDATABASE','tests');

$link = mysqli_connect(MYSQLHOST, MYSQLUSER, MYSQLPASS, MYSQLDATABASE);

$prev_name = '';
$prev_name_b = '';
$prev_name_c = '';

$query_select = "SELECT name, name_b, name_c
FROM A
LEFT OUTER JOIN B
ON A.ID = B.Parent_ID
LEFT OUTER JOIN C
ON B.ID = C.Parent_ID
ORDER BY A.ID, B.ID, C.ID";

$result_select = mysqli_query($link, $query_select) or die(mysql_error());
$rows = array();
while($menurow = mysqli_fetch_array($result_select))
{
if ($menurow['name'] != $prev_name)
{
if (isset($name_c_object)) unset($name_c_object);
if (isset($name_b_object)) unset($name_b_object);
if (isset($name_object)) unset($name_object);
$name_object = new ul(1);
$prev_name = $menurow['name'];
$name_object->li($prev_name);
}
if ($menurow['name_b'] != $prev_name_b)
{
if (isset($name_c_object)) unset($name_c_object);
if (isset($name_b_object)) unset($name_b_object);
$name_b_object = new ul(3);
$prev_name_b = $menurow['name_b'];
$name_b_object->li($prev_name_b);
if (isset($name_c_object)) unset($name_c_object);
$name_c_object = new ul(5);
}
$name_c_object->li($menurow['name_c']);
}

if (isset($name_c_object)) unset($name_c_object);
if (isset($name_b_object)) unset($name_b_object);
if (isset($name_object)) unset($name_object);

class ul
{
private $out_li = false;
private $num_tab = 0;
public function __CONSTRUCT($num_tab)
{
$this->num_tab = $num_tab;
echo str_repeat("\t", $this->num_tab)."<ul>\r\n";
}
public function __DESTRUCT()
{
if ($this->out_li) echo str_repeat("\t", $this->num_tab)."\t</li>\r\n";
echo str_repeat("\t", $this->num_tab)."</ul>\r\n";
}
public function li($li)
{
if ($this->out_li) echo str_repeat("\t", $this->num_tab)."\t</li>\r\n";
echo str_repeat("\t", $this->num_tab)."\t<li>\r\n";
echo str_repeat("\t", $this->num_tab)."\t\t$li\r\n";
$this->out_li = true;
}
}

РЕДАКТИРОВАТЬ снова

Я переосмыслил и обдумал это: —

<?php

#------ database connections -------
define('MYSQLHOST','localhost');
define('MYSQLUSER','root');
define('MYSQLPASS','');
define('MYSQLDATABASE','tests');

$link = mysqli_connect(MYSQLHOST, MYSQLUSER, MYSQLPASS, MYSQLDATABASE);

$prev_id_a = 0;
$prev_id_b = 0;
$prev_id_c = 0;

$query_select = "SELECT name, name_b, name_c, A.ID AS aid, B.ID AS bid, C.ID AS cid
FROM A
LEFT OUTER JOIN B
ON A.ID = B.Parent_ID
LEFT OUTER JOIN C
ON B.ID = C.Parent_ID
ORDER BY A.ID, B.ID, C.ID";

$result_select = mysqli_query($link, $query_select) or die(mysql_error());
$rows = array();

$name_a_object = new ul(0);

while($menurow = mysqli_fetch_array($result_select))
{
if ($menurow['aid'] != $prev_id_a)
{
if (isset($name_c_object)) unset($name_c_object);
if (isset($name_b_object)) unset($name_b_object);
$name_a_object->li($menurow['name']);
$name_b_object = new ul(2);
$prev_id_a = $menurow['aid'];
}
if ($menurow['bid'] != $prev_id_b)
{
if (isset($name_c_object)) unset($name_c_object);
$name_b_object->li($menurow['name_b']);
$name_c_object = new ul(4);
$prev_id_b = $menurow['bid'];
}
$name_c_object->li($menurow['name_c']);
}

if (isset($name_c_object)) unset($name_c_object);
if (isset($name_b_object)) unset($name_b_object);
if (isset($name_a_object)) unset($name_a_object);

class ul
{
private $num_tab = 0;
private $li_output = false;
public function __CONSTRUCT($num_tab, $li=null)
{
$this->num_tab = $num_tab;
echo str_repeat("\t", $this->num_tab)."<ul>\r\n";
if ($li != null)
{
echo str_repeat("\t", $this->num_tab)."\t<li>\r\n";
echo str_repeat("\t", $this->num_tab)."\t\t$li\r\n";
}
}
public function __DESTRUCT()
{
if ($this->li_output)
{
echo str_repeat("\t", $this->num_tab)."\t</li>\r\n";
}
echo str_repeat("\t", $this->num_tab)."</ul>\r\n";
}
public function li($li)
{
if ($this->li_output)
{
echo str_repeat("\t", $this->num_tab)."\t</li>\r\n";
}
echo str_repeat("\t", $this->num_tab)."\t<li>\r\n";
echo str_repeat("\t", $this->num_tab)."\t\t$li\r\n";
$this->li_output = true;
}
}
1

Другие решения

Все запросы возвращают данные в одном измерении. Но вы можете обойти это так:

SELECT x.level,x.id,x.name
FROM
(
SELECT 1 as level, id as id, name as name
, id as id_1,-1 as id_2, -1 as id_3
FROM table_a
WHERE 1
UNION
SELECT 2 as level, id as id, name_b as name
, Parent_ID as id_1,id as id_2, -1 as id_3
FROM table_b
WHERE 1
UNION
SELECT 3 as level, c.id as id, c.name_c as name
, b.Parent_ID as id_1,b.id as id_2, c.id as id_3
FROM table_c c LEFT JOIN table_b b ON c.Parent_ID=b.id
WHERE 1
) x
WHERE 1
ORDER BY id_1,id_2,id_3

что должно вернуться

Level | Name
1       Category 1
2       Subcategory 1
3       Tertiarycategory 1
2       Subcategory 2
3       Tertiarycategory 2
3       Tertiarycategory 3
1       Category 2
2       Subcategory 3
3       Tertiarycategory 4

и код PHP это:

$r = $db->query($query);
$level = 0;
while($x=mysql_fetch_object($r))
{
while($level < $x->level)
{
echo '<ul>';
$level++;
}
while($level > $x->level)
{
echo '</ul>';
$level--;
}
echo '<li>'$x->ID.'#'.$x->name;
}
while($level-- > 0)
echo '</ul>';

редактировать: Или вместо того, чтобы оставить работу по сборке MySQL, давайте сделаем это просто внутри PHP

$r1 = $db->query("SELECT * FROM table_a order by ID");
$r2 = $db->query("SELECT * FROM table_b order by Parent_ID");
$r3 = $db->query("SELECT table_c.*
FROM table_c
LEFT JOIN table_b ON table_c.Parent_ID=table_b.ID
order by table_b.Parent_ID");

$e1 = mysql_fetch_object($r1);
$e2 = mysql_fetch_object($r2);
$e3 = mysql_fetch_object($r3);

echo "<ul>";
while($e1)
{
echo "<li>".htmlentities($e1->name);
if($e2 && $e2->Parent_ID==$e1->ID)
{
echo "<ul>";
while($e2 && $e2->Parent_ID==$e1->ID)
{
echo "<li>".htmlentities($e2->name_b);
if($e3 && $e3->Parent_ID==$e2->ID)
{
echo "<ul>";
while($e3 && $e3->Parent_ID==$e2->ID)
{
echo "<li>".htmlentities($e3->name_3);
$e3 = mysql_fetch_object($r3);
}
echo "</ul>";
}
$e2 = mysql_fetch_object($r2);
}
echo "</ul>";
}
$e1 = mysql_fetch_object($r1);
}
echo "</ul>";
1

Это код в настоящее время, но результаты не возвращаются.

<?php
$host = "localhost"; //server
$db = "xx"; //database name
$user = "xx"; //dabases user name
$pwd = "xx"; //password

//connecting to server and creating link to database
$dblink = mysqli_connect($host, $user, $pwd, $db);

$r1 = $dblink->query("SELECT * FROM auction_a_categories order by ID");
$r2 = $dblink->query("SELECT * FROM auction_b_categories order by Parent_ID");
$r3 = $dblink->query("SELECT auction_c_categories.*
FROM auction_c_categories
LEFT JOIN auction_b_categories ON auction_c_categories.Parent_ID=auction_b_categories.ID
order by auction_b_categories.Parent_ID");

$e1 = mysql_fetch_object($r1);
$e2 = mysql_fetch_object($r2);
$e3 = mysql_fetch_object($r3);

echo "<ul>";
while($e1)
{
echo "<li>".htmlentities($e1->name);
if($e2 && $e2->Parent_ID==$e1->ID)
{
echo "<ul>";
while($e2 && $e2->Parent_ID==$e1->ID)
{
echo "<li>".htmlentities($e2->name_b);
if($e3 && $e3->Parent_ID==$e2->ID)
{
echo "<ul>";
while($e3 && $e3->Parent_ID==$e2->ID)
{
echo "<li>".htmlentities($e3->name_3);
$e3 = mysql_fetch_object($r3);
}
echo "</ul>";
}
$e2 = mysql_fetch_object($r2);
}
echo "</ul>";
}
$e1 = mysql_fetch_object($r1);
}
echo "</ul>";

?>
0
По вопросам рекламы [email protected]