sql >> データベース >  >> RDS >> Mysql

mysql階層は自己結合し、すべてのサブカテゴリを取得します

    Please Noteをお読みください 最初に一番下に。よし、あなたは戻ってきた。

    再帰的な階層検索のためのストアドプロシージャの作成。

    レベルごとにそれを望んでいなかったことに注意してください、しかしそれは簡単に行うことができます。

    スキーマ:

    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
    

    ストアドプロシージャの作成:

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

    テストストアドプロシージャ:

    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
    

    この回答 を変更しただけであることに注意してください あなたのニーズのために数ヶ月前から私のもの。

    注意

    上記は説明のみを目的としています。実際の状況では、ストアドプロシージャにテーブルを作成することは決してありません。 DDLのオーバーヘッドは重要です。代わりに、セッションの概念を持つ既存の非一時テーブルを使用します。そして、行われたセッションのために行からそれをきれいにします。ですから、上記をストローマン以上のものと見なさないでください。あなたがそれをよりパフォーマンスの高いものにするのを待っています。それが紛らわしいかどうか尋ねてください。




    1. PostgreSQLがpg_catalogテーブルからパーミッションを取り消す

    2. postgresでシングルユーザーモードでテーブルを作成する

    3. PostgreSQLの日付に日を追加する

    4. SQLclでクエリ結果をフォーマットする2つの方法(Oracle)