Baca Please Note
di bagian bawah dulu. Oke bagus, Anda kembali.
Pembuatan Prosedur Tersimpan untuk pengambilan hierarki seperti rekursif.
Perhatikan, Anda tidak menginginkannya berdasarkan level tetapi itu dapat dilakukan dengan mudah.
Skema:
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
Buat Proc Tersimpan:
-- 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
$$
Uji Proc Tersimpan:
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
Catatan Saya hanya memodifikasi Jawaban ini milik saya dari beberapa bulan yang lalu untuk kebutuhan Anda.
Harap Diperhatikan
Di atas hanya untuk tujuan ilustrasi. Dalam situasi dunia nyata, saya tidak akan pernah membuat tabel di proc yang tersimpan. Overhead DDL signifikan. Sebagai gantinya, saya akan menggunakan tabel non temp yang sudah ada sebelumnya dengan konsep sesi. Dan bersihkan dari baris untuk sesi selesai. Jadi jangan anggap hal di atas lebih dari sekadar manusia jerami, menunggu Anda untuk membuatnya lebih berkinerja seperti itu. Tanyakan apakah itu membingungkan.