Mysql
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Mysql

Hệ thống phân cấp mysql tự tham gia, truy xuất tất cả các danh mục con

Đọc Please Note ở dưới cùng trước. Được rồi, bạn đã trở lại.

Tạo một thủ tục được lưu trữ để truy xuất phân cấp giống như đệ quy.

Lưu ý, bạn không muốn nó theo cấp độ nhưng điều đó có thể dễ dàng thực hiện được.

Lược đồ:

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

Tạo Proc được Lưu trữ:

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

Test đã lưu trữ Proc:

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

Lưu ý rằng tôi chỉ sửa đổi Câu trả lời này của tôi từ vài tháng trước cho nhu cầu của bạn.

Xin lưu ý

Trên đây chỉ mang tính chất minh họa. Trong tình huống thực tế, tôi sẽ không bao giờ tạo các bảng trong một chương trình được lưu trữ. Chi phí DDL là đáng kể. Thay vào đó, tôi sẽ sử dụng các bảng không tạm thời có sẵn từ trước với khái niệm phiên. Và làm sạch nó ra khỏi hàng cho phiên đã hoàn thành. Vì vậy, đừng coi những điều trên như một người đàn ông rơm, hãy chờ đợi bạn thực hiện nó thành công hơn. Hỏi xem điều đó có gây nhầm lẫn không.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Làm thế nào để bảo mật tệp cấu hình cơ sở dữ liệu trong dự án?

  2. Các dấu ngoặc kép khác nhau của MySQL

  3. Khi nào thì đóng kết nối MySQL bằng node-mysql?

  4. truy vấn mySQL để chọn con

  5. Có cách nào để chèn một giá trị lớn vào DB mysql mà không thay đổi max_allowed_packet không?