Vous êtes sur la page 1sur 4

1

GeneratingDepthbasedtreefromHierarchicalDatainMySQL(noCTEs)
HiFormanydaysIhavebeenworkingonthisprobleminMySQL,howeverIcannotfigureitout.Doanyofyouhavesuggestions?
Basically,Ihaveacategorytablewithdomainslike: id , name (nameofcategory),and parent (idofparentofthecategory).
ExampleData:
1Fruit0
2Apple1
3pear1
4FujiApple2
5AusApple2
6SydneyAPPLE5
....

Therearemanylevels,possiblymorethan3levels.Iwanttocreateansqlquerythatgroupsthedatasaccordingtohehierarchy:parent>child
>grandchild>etc.
Itshouldoutputthetreestructure,asfollows:
1Fruit0
^2Apple1
^4FujiApple2
5AusApple2
^6SydneyApple5
3pear1

CanIdothisusingasingleSQLquery?Thealternative,whichItriedanddoeswork,isthefollowing:
SELECT*FROMcategoryWHEREparent=0

Afterthis,Iloopthroughthedataagain,andselecttherowswhereparent=id.Thisseemslikeabadsolution.BecauseitismySQL,CTEscannot
beused.
mysql hierarchicaldata commontableexpression
editedJun16'12at1:49

stillreadingandunderstandingallsolution,nosurewhichonetopick. bluedream Mar14'11at0:10


Toobadyouaren'tusingMSSQLtheHierachyIdfeaturesolvesthisproblemandisextremelyfast.

KirkBroadhurstMar14'11at12:39
stackoverflow.com/questions/4048151/ orangepips Mar14'11at18:54
addedsomeadditionalinfotomyanswer:) JonBlack Mar15'11at1:53

4Answers

Youcandoitinasinglecallfromphptomysqlifyouuseastoredprocedure:

Examplecalls
mysql>callcategory_hier(1);
++++++
|cat_id|category_name|parent_cat_id|parent_category_name|depth|
++++++
|1|Location|NULL|NULL|0|
|3|USA|1|Location|1|
|4|Illinois|3|USA|2|
|5|Chicago|3|USA|2|
++++++
4rowsinset(0.00sec)

$sql=sprintf("callcategory_hier(%d)",$id);

Hopethishelps:)

Fullscript
Testtablestructure:
droptableifexistscategories;
createtablecategories
(
cat_idsmallintunsignednotnullauto_incrementprimarykey,
namevarchar(255)notnull,
parent_cat_idsmallintunsignednull,
key(parent_cat_id)
)
engine=innodb;

askedMar13'11at17:23

DavidManheim

bluedream

1,830

154

12

34

13

help

Testdata:
insertintocategories(name,parent_cat_id)values
('Location',null),
('USA',1),
('Illinois',2),
('Chicago',2),
('Color',null),
('Black',3),
('Red',3);

Procedure:
dropprocedureifexistscategory_hier;
delimiter#
createprocedurecategory_hier
(
inp_cat_idsmallintunsigned
)
begin
declarev_donetinyintunsigneddefault0;
declarev_depthsmallintunsigneddefault0;
createtemporarytablehier(
parent_cat_idsmallintunsigned,
cat_idsmallintunsigned,
depthsmallintunsigneddefault0
)engine=memory;
insertintohierselectparent_cat_id,cat_id,v_depthfromcategorieswherecat_id=
p_cat_id;
/*http://dev.mysql.com/doc/refman/5.0/en/temporarytableproblems.html*/
createtemporarytabletmpengine=memoryselect*fromhier;
whilenotv_donedo
ifexists(select1fromcategoriespinnerjoinhieronp.parent_cat_id=hier.cat_id
andhier.depth=v_depth)then
insertintohier
selectp.parent_cat_id,p.cat_id,v_depth+1fromcategoriesp
innerjointmponp.parent_cat_id=tmp.cat_idandtmp.depth=v_depth;
setv_depth=v_depth+1;
truncatetabletmp;
insertintotmpselect*fromhierwheredepth=v_depth;
else
setv_done=1;
endif;
endwhile;
select
p.cat_id,
p.nameascategory_name,
b.cat_idasparent_cat_id,
b.nameasparent_category_name,
hier.depth
from
hier
innerjoincategoriesponhier.cat_id=p.cat_id
leftouterjoincategoriesbonhier.parent_cat_id=b.cat_id
orderby
hier.depth,hier.cat_id;
droptemporarytableifexistshier;
droptemporarytableifexiststmp;
end#

Testruns:
delimiter;
callcategory_hier(1);
callcategory_hier(2);

SomeperformancetestingusingYahoogeoplanetplacesdata
droptableifexistsgeoplanet_places;
createtablegeoplanet_places
(
woe_idintunsignednotnull,
iso_codevarchar(3)notnull,
namevarchar(255)notnull,
langvarchar(8)notnull,
place_typevarchar(32)notnull,
parent_woe_idintunsignednotnull,
primarykey(woe_id),
key(parent_woe_id)
)
engine=innodb;
mysql>selectcount(*)fromgeoplanet_places;

++
|count(*)|
++
|5653967|
++

sothat's5.6millionrows(places)inthetablelet'sseehowtheadjacencylist
implementation/storedprocedurecalledfromphphandlesthat.
1recordsfetchedwithmaxdepth0in0.001921secs
250recordsfetchedwithmaxdepth1in0.004883secs
515recordsfetchedwithmaxdepth1in0.006552secs
822recordsfetchedwithmaxdepth1in0.009568secs
918recordsfetchedwithmaxdepth1in0.009689secs
1346recordsfetchedwithmaxdepth1in0.040453secs
5901recordsfetchedwithmaxdepth2in0.219246secs
6817recordsfetchedwithmaxdepth1in0.152841secs
8621recordsfetchedwithmaxdepth3in0.096665secs
18098recordsfetchedwithmaxdepth3in0.580223secs
238007recordsfetchedwithmaxdepth4in2.003213secs

Overalli'mprettypleasedwiththosecoldruntimesasIwouldn'tevenbegintoconsiderreturning
tensofthousandsofrowsofdatatomyfrontendbutwouldratherbuildthetreedynamically
fetchingonlyseverallevelspercall.Ohandjustincaseyouwerethinkinginnodbisslowerthan
myisamthemyisamimplementationItestedwastwiceasslowinallcounts.
Morestuffhere:http://pastie.org/1672733
Hopethishelps:)
editedApr2at21:00

answeredMar13'11at17:40

Nathanael
2,016

JonBlack
15

29

10.9k

29

33

Ifearthismethodwillhavesomeseriousperformanceissues. CyberDude Mar13'11at17:46

6 fearnotitdoesnt.JonBlack Mar13'11at18:26
iamtryingthismethod,writingmyownone,thenmaybeiwillcheckouttheprocessingtime bluedream

Mar14'11at0:10
youcandosomeperformanceandstresstestingwithYahooGeoPlanetdatafoundhere:

developer.yahoo.com/geo/geoplanet/dataJonBlack Mar14'11at21:53
1 Coolsolution.Imodifieditabittosupportbuildingupthe"fullpath"forthename,andtoacceptNULLid
paramtoprintALLparentsandtheirchildren.Codeisatgist.github.com/jdmullin/9377818JeremyMullin
Mar5'14at22:20

TherearetwocommonwaysofstoringhierarchicaldatainanRDBMS:adjacencylists(which
youareusing)andnestedsets.Thereisaverygoodwriteupaboutthesealternativesin
ManagingHierarchicalDatainMySQL.Youcanonlydowhatyouwantinasinglequerywiththe
nestedsetmodel.However,thenestedsetmodelmakesitmoreworktoupdatethehierarchical
structure,soyouneedtoconsiderthetradeoffsdependingonyouroperationalrequirements.
editedOct30'11at20:47

answeredMar13'11at17:31

PaloEbermann
45.7k

80

TedHopp
141

155k

26

228

329

thanks,willreadthearticle bluedream Mar14'11at0:11

Youcan'tachievethisusingasinglequery.Yourhierarchicaldatamodelisineffectiveinthis
case.Isuggestyoutrytwootherwaysofstoringhierarchicaldatainadatabase:theMPTT
modelorthe"lineage"model.Usingeitherofthosemodelsallowsyoutodotheselectyouwantin
asinglego.
Hereisanarticlewithfurtherdetails:http://articles.sitepoint.com/article/hierarchicaldata
database
editedMar13'11at17:36

answeredMar13'11at17:30

CyberDude
4,794

12

Here'sa descriptionofthelineagemodel. TedHopp Mar13'11at17:46

2 Whydidyouremovethe MySQL tag?MartinSmithMar14'11at0:03


thanks,ithinkididnotremove.... bluedream Mar14'11at0:08
ThisisnotMySQLspecific.It'sageneralSQLsubject. CyberDude Mar14'11at6:52

6 @Martin:actuallyallothermajorDBMSsupportrecursiveCTEexceptMySQLa_horse_with_no_name
Mar14'11at12:39

34

Thelinearway:
Iamusingauglyfunctiontocreateatreeinasimplestringfield.
/topictitle
/001message1
/002message2
/002/001replytomessage2
/002/001/001/replytoreply
/003message3
etc...

thetablecanbeusedtoselectalltherowsinthetreeorderwithasimpleSQL
Query:
select*frommorum_messageswherem_topic=1234orderbym_linearasc
INSERT isjustselecttheparentlinear(andchildren)andcalculatethestringas
needed.
selectM_LINEARFROMforum_messagesWHEREm_topic=1234andM_LINEARLIKE'{0}/___'ORDER
BYM_LINEARDESClimit0,1
/*{0}m_linearoftheparentmessage*/
DELETE

issimpleasdeletethemessage,ordeletebylinearallrepliesoftheparent

one.
answeredMay4'12at9:39

MosheL
573

Vous aimerez peut-être aussi