Mysql Multiple Joins, чтобы изобразить макет таблицы моих категорий - PullRequest
0 голосов
/ 11 марта 2011

Я пытаюсь изобразить список категорий, суб и суб и так далее.

<b>Root             Sub Level 1</b>
Personal income  Adelaide IT Solutions (AITS)
Personal income  DJ
Personal income  Ebay Sales
Personal income  IAG
Rental income    Cash Grove Pasadena
Rental income    Winston Ave Cumberland Park
Personal income  Misc Income

Я написал следующий SQL-оператор, который возвращает результаты, но только для случаев, когда он совпадает с объединением, например, если у меня объединение, достигающее глубины 3 уровня, оно будет перечислять только те категории, в которых есть категория с такой глубиной .

Я предполагаю, что должен использовать вложенные селекты или что-то подобное, но не знаю, как это сделать.

SELECT
    c.name as 'Root',
    s.name as 'Sub Level 1',
    s2.name as 'Sub Level 2',
    s3.name as 'Sub Level 3'
FROM catergories c
    INNER JOIN catergories s ON c.id = s.parent
    INNER JOIN catergories s2 ON s.id = s2.parent
    INNER JOIN catergories s3 ON s2.id = s3.parent

Любая помощь будет принята с благодарностью.

Ответы [ 2 ]

0 голосов
/ 11 марта 2011

Достаточно простая реализация хранимой процедуры нерекурсивного списка смежности, которая позволяет сделать один вызов с уровня приложения к БД и получить необходимую иерархию.

mysql> call employees_hier(1);
+--------+-----------------+-------------+-----------------+-------+
| emp_id | emp_name        | boss_emp_id | boss_name       | depth |
+--------+-----------------+-------------+-----------------+-------+
|      1 | f00             |        NULL | NULL            |     0 |
|      2 | ali later       |           1 | f00             |     1 |
|      3 | megan fox       |           1 | f00             |     1 |
|      4 | jessica alba    |           3 | megan fox       |     2 |
|      5 | eva longoria    |           3 | megan fox       |     2 |
|      6 | keira knightley |           5 | eva longoria    |     3 |
|      7 | liv tyler       |           6 | keira knightley |     4 |
|      8 | sophie marceau  |           6 | keira knightley |     4 |
+--------+-----------------+-------------+-----------------+-------+
8 rows in set (0.00 sec)

Очевидно, замените сотрудников своими категориями ...

drop table if exists employees;
create table employees
(
emp_id smallint unsigned not null auto_increment primary key,
name varchar(255) not null,
boss_id smallint unsigned null,
key (boss_id)
)
engine = innodb;

insert into employees (name, boss_id) values
('f00',null), 
  ('ali later',1), 
  ('megan fox',1), 
      ('jessica alba',3), 
      ('eva longoria',3), 
         ('keira knightley',5), 
            ('liv tyler',6), 
            ('sophie marceau',6);


drop procedure if exists employees_hier;

delimiter #

create procedure employees_hier
(
in p_emp_id smallint unsigned
)
begin

declare v_done tinyint unsigned default(0);
declare v_dpth smallint unsigned default(0);

create temporary table hier(
 boss_id smallint unsigned, 
 emp_id smallint unsigned, 
 depth smallint unsigned
)engine = memory;

insert into hier select boss_id, emp_id, v_dpth from employees where emp_id = p_emp_id;

/* http://dev.mysql.com/doc/refman/5.0/en/temporary-table-problems.html */

create temporary table emps engine=memory select * from hier;

while not v_done do

    if exists( select 1 from employees e inner join hier on e.boss_id = hier.emp_id and hier.depth = v_dpth) then

        insert into hier select e.boss_id, e.emp_id, v_dpth + 1 
            from employees e inner join emps on e.boss_id = emps.emp_id and emps.depth = v_dpth;

        set v_dpth = v_dpth + 1;            

        truncate table emps;
        insert into emps select * from hier where depth = v_dpth;

    else
        set v_done = 1;
    end if;

end while;

select 
 e.emp_id,
 e.name as emp_name,
 p.emp_id as boss_emp_id,
 p.name as boss_name,
 hier.depth
from 
 hier
inner join employees e on hier.emp_id = e.emp_id
left outer join employees p on hier.boss_id = p.emp_id;

drop temporary table if exists hier;
drop temporary table if exists emps;

end #

delimiter ;

-- call this sproc from your php

call employees_hier(1);
0 голосов
/ 11 марта 2011

Предполагая, что максимальная глубина составляет 3 уровня, простейшая реализация будет использовать LEFT JOIN для отображения всех категорий в корневом столбце и их подкатегорий, если они существуют:

SELECT
 c.name as 'Root',
 s.name as 'Sub Level 1',
 s2.name as 'Sub Level 2',
 s3.name as 'Sub Level 3'
FROM catergories c
 LEFT JOIN catergories s ON c.id = s.parent
 LEFT JOIN catergories s2 ON s.id = s2.parent
 LEFT JOIN catergories s3 ON s2.id = s3.parent

С помощью приведенного выше запроса у вас будет много дубликатов - ВСЕ категории будут отображаться как корневые, а некоторые из них снова будут отображаться как подкатегории на разных уровнях. Чтобы иметь в качестве root только Parents, я думаю, вы можете добавить правило:

SELECT
 c.name as 'Root',
 s.name as 'Sub Level 1',
 s2.name as 'Sub Level 2',
 s3.name as 'Sub Level 3'
FROM catergories c
 LEFT JOIN catergories s ON c.id = s.parent
 LEFT JOIN catergories s2 ON s.id = s2.parent
 LEFT JOIN catergories s3 ON s2.id = s3.parent
WHERE c.parent IS NULL  
-- or parent=-1, or whatever a category with no parent has for in the parent column
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...