Mysql
 sql >> Baza danych >  >> RDS >> Mysql

hierarchia mysql samodołączanie, pobieranie wszystkich podkategorii

Przeczytaj Please Note najpierw na dole. Dobrze, wróciłeś.

Tworzenie procedury składowanej do rekurencyjnego wyszukiwania hierarchii.

Pamiętaj, że nie chciałeś tego według poziomów, ale można to łatwo zrobić.

Schemat:

create table category
(   category_id int not null auto_increment primary key,
    category_name varchar(40) not null,
    parent_id int null,  -- index on this column not a shabby idea
    unique key (category_name)
);

insert category(category_name,parent_id) values ('car',null),('food',null); -- 1,2
insert category(category_name,parent_id) values ('ford',1),('chevy',1),('fruit',2); -- 3,4,5
insert category(category_name,parent_id) values ('economy',3),('escort',6),('exhaust',7); -- 6,7,8
insert category(category_name,parent_id) values ('chassis',7),('loud',8),('banana',5); -- 9,10,11
-- ok granted I could have explicity inserted category_id to make it more obvious

Utwórz przechowywaną procedurę:

-- drop procedure showHierarchyBelow;
delimiter $$
create procedure showHierarchyBelow
(
catname varchar(40)
)
BEGIN
    -- deleteMe parameter means i am anywhere in hierarchy of role
    -- and i want me and all my offspring deleted (no orphaning of children or theirs)
    declare bDoneYet boolean default false;
    declare working_on int;
    declare theCount int;
    declare findFirst int;

    select ifnull(category_id,0) into findFirst from category where category_name=catname;

    CREATE TABLE xx_RecursishHelper_xx
    (   -- it's recurshish, not recursive
        category_id int not null,
        processed int not null
    );
    if isnull(findFirst) then
        set findFirst=0;
    end if;
    insert into xx_RecursishHelper_xx (category_id,processed) select findFirst,0;
    if (findFirst=0) then
        set bDoneYet=true;
    else
        set bDoneYet=false;
    end if;

    while (!bDoneYet) do
        -- I am not proud of this next line, but oh well
        select count(*) into theCount from xx_RecursishHelper_xx where processed=0;

        if (theCount=0) then 
            -- found em all
            set bDoneYet=true;
        else
            -- one not processed yet, insert its children for processing
            SELECT category_id INTO working_on FROM xx_RecursishHelper_xx where processed=0 limit 1;
            insert into xx_RecursishHelper_xx (category_id,processed)
            select category_id,0 from category
            where parent_id=working_on;

            -- mark the one we "processed for children" as processed
            update xx_RecursishHelper_xx set processed=1 where category_id=working_on;
        end if;
    end while;

    delete from xx_RecursishHelper_xx where category_id=findFirst;

    select x.category_id,c.category_name
    from xx_RecursishHelper_xx x
    join category c
    on c.category_id=x.category_id;

    drop table xx_RecursishHelper_xx;
END
$$

Testuj przechowywany proces:

call showHierarchyBelow('food');
+-------------+---------------+
| category_id | category_name |
+-------------+---------------+
|           5 | fruit         |
|          11 | banana        |
+-------------+---------------+

call showHierarchyBelow('car');
+-------------+---------------+
| category_id | category_name |
+-------------+---------------+
|           3 | ford          |
|           4 | chevy         |
|           6 | economy       |
|           7 | escort        |
|           8 | exhaust       |
|           9 | chassis       |
|          10 | loud          |
+-------------+---------------+

call showHierarchyBelow('ford');
+-------------+---------------+
| category_id | category_name |
+-------------+---------------+
|           6 | economy       |
|           7 | escort        |
|           8 | exhaust       |
|           9 | chassis       |
|          10 | loud          |
+-------------+---------------+

call showHierarchyBelow('xxx');
-- no rows

Uwaga:Zmodyfikowałem tylko tę Odpowiedź moje sprzed kilku miesięcy dla Twoich potrzeb.

Uwaga

Powyższe ma jedynie charakter poglądowy. W rzeczywistych sytuacjach nigdy nie stworzyłbym tabel w przechowywanym proc. Obciążenie DDL jest znaczące. Zamiast tego użyłbym wcześniej istniejących tabel nie tymczasowych z koncepcją sesji. I wyczyść go z rzędów na skończoną sesję. Więc nie traktuj powyższego jako bardziej niż słomianego człowieka, czekając, aż sprawisz, że będzie bardziej wydajny jako taki. Zapytaj, czy to jest mylące.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Co jest lepsze, niejawne czy jawne sprzężenie?

  2. mysql wybrać int jako walutę lub przekonwertować int na format walutowy?

  3. Jak prawidłowo obsługiwać międzynarodowy znak w PHP / MySQL / Apache

  4. Używanie % dla hosta podczas tworzenia użytkownika MySQL

  5. Wstawianie zbiorcze PHP