树形结构mysql设计_常见数据库设计(4)——树形结构数据

1 概述

树形数据,主要关注的是:

1> 如何将数据高效地以树形的形式展现给用户

2> 通过某个节点找到所有的父节点。

3> 获取某个节点的所有的后继节点(包括子节点的子节点)

至于添加、修改、删除和通过一个父节点获取对应的子节点,都是可以很容易的实现。

2 邻接模型

2.1业务:文件存放位置,在档案管理中,需要为文件的存放位置建模,文件存在抽屉,然后抽屉在某个柜子中,柜子在某个房间中。

2.2表结构:

400fd969365a30d9f106cd959a203787.png

2.3备注

可以在表中再加入一个level_num字段(表示所处在树的深度),这样就少了那一个递归查询的操作,但是在管理上有做一些处理。

2.4测试数据

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.pngView Code

IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Location]'))DROP TABLE [dbo].LocationGO

--位置表

CREATE TABLEdbo.Location

(

idint,

namenvarchar(50),

parent_idint,

order_noint);INSERT INTOdbo.LocationSELECT 1,'房间1',0,1

UNION ALL

SELECT 2,'柜子11',1,2

UNION ALL

SELECT 3,'抽屉111',2,3

UNION ALL

SELECT 4,'抽屉122',2,4

UNION ALL

SELECT 5,'柜子12',1,5

UNION ALL

SELECT 6,'抽屉121',5,6

UNION ALL

SELECT 7,'房间2',0,7

UNION ALL

SELECT 8,'柜子21',7,8

UNION ALL

SELECT 9,'柜子22',7,9

UNION ALL

SELECT 10,'房间3',0,10

2.5 如何将数据高效地以树形的形式展现给用户,执行SQL:

;WITH locationT AS(SELECT L.id,L.name,L.parent_id,L.order_no,0 ASlevelLFROM Location ASLWHERE L.parent_id=0

UNION ALL

SELECT LC.id,LC.name,LC.parent_id,LC.order_no,LP.levelL+1

FROM Location ASLCINNER JOIN locationT AS LP ON LC.parent_id=LP.id

)SELECT *,CASElevelLWHEN 0 THEN '|-'+nameWHEN 1 THEN '|-|-'+nameWHEN 2 THEN '|-|-|-'+nameWHEN 3 THEN '|-|-|-|-'+nameEND ASlevel_nameFROMlocationTORDER BY order_no

结果:

bdcdade5fb7842734f8f8b4c514b2450.png

备注:其中CASElevelLWHEN 0 THEN '|-'+nameWHEN 1 THEN '|-|-'+nameWHEN 2 THEN '|-|-|-'+nameWHEN 3 THEN '|-|-|-|-'+nameEND ASlevel_name 为树的深度大概可知,不会很深时,可以这样做,但是如果树的深度不可知,可以用下面的SQL,不过效率会低一些:

SELECT * ,replace(replace(str(0,(levelL+1)),' ','0'),'0','|-')+name level_nameFROMlocationTORDER BY order_no

2.6 通过某个节点找到所有的父节点,执行SQL:

;WITH locationT(id,name_level,name,parent_id,order_no,levelL) AS(SELECT L.id,CAST(L.name AS NVARCHAR(1000)) AS name_level,L.name,L.parent_id,L.order_no,0 ASlevelLFROM Location ASLWHERE L.parent_id=0

UNION ALL

SELECT LC.id,CAST(LP.name_level+','+LC.name AS NVARCHAR(1000)) AS name_level,LC.name,LC.parent_id,LC.order_no,LP.levelL+1

FROM Location ASLCINNER JOIN locationT AS LP ON LC.parent_id=LP.id

)SELECT *

FROMlocationTWHERE name='抽屉111'

ORDER BY order_no

结果:

1ff42f223db1df3fecaab8f0c1356a80.png

2.7 获取某个节点的所有子节点

;WITH locationT AS(SELECT L.id,L.name,L.parent_id,L.order_no,0 ASlevelLFROM Location ASLWHERE L.name='房间1'

UNION ALL

SELECT LC.id,LC.name,LC.parent_id,LC.order_no,LP.levelL+1

FROM Location ASLCINNER JOIN locationT AS LP ON LC.parent_id=LP.id

)SELECT *,CASElevelLWHEN 0 THEN '|-'+nameWHEN 1 THEN '|-|-'+nameWHEN 2 THEN '|-|-|-'+nameWHEN 3 THEN '|-|-|-|-'+nameEND ASlevel_nameFROMlocationTORDER BY order_no

结果:

3a59bc3d4868a7921f4439c63839d551.png

3 物化路径模型

3.1业务:文件存放位置,在档案管理中,需要为文件的存放位置建模,文件存在抽屉,然后抽屉在某个柜子中,柜子在某个房间中。

3.2表结构:

9fb093270c40f463164493aba23cff51.png

3.3备注:

此时不加入parent_id也可以完成操作,但是加入parent_id可以简化管理的操作,Level_num也可以不加入,但是加入后可以在显示数据时简化操作。

3.4测试数据:

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.pngView Code

IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Location2]'))DROP TABLE [dbo].Location2GO

--位置表

CREATE TABLEdbo.Location2

(

idint,

namenvarchar(50),

level_codevarchar(1000),

parent_idint,

level_numint);INSERT INTOdbo.Location2SELECT 1,'房间','001',0,1

UNION ALL

SELECT 2,'柜子','001.001',1,2

UNION ALL

SELECT 3,'抽屉','001.001.001',2,3

UNION ALL

SELECT 4,'抽屉','001.001.002',2,3

UNION ALL

SELECT 5,'柜子','001.002',1,2

UNION ALL

SELECT 6,'抽屉','001.002.001',5,3

UNION ALL

SELECT 7,'房间','002',0,1

UNION ALL

SELECT 8,'柜子','002.001',7,2

UNION ALL

SELECT 9,'柜子','002.002',7,2

UNION ALL

SELECT 10,'房间','003',0,1

2.5 如何将数据高效地以树形的形式展现给用户,执行SQL:

SELECT *,CASElevel_numWHEN 0 THEN '|-'+nameWHEN 1 THEN '|-|-'+nameWHEN 2 THEN '|-|-|-'+nameWHEN 3 THEN '|-|-|-|-'+nameEND ASlevel_nameFROM Location2 ASLORDER BY level_code

结果:

86607654ea81c8d6d7cee89bccb600dc.png

2.6 通过某个节点找到所有的父节点,执行SQL:

DECLARE @level_code varchar(1000)='001.001.001';

;WITH locationRowT AS(SELECT TOP 100 PERCENT * ,ROW_NUMBER()OVER(ORDER BY id) ASrow_idFROM Location2 ASLORDER BYlevel_code

)SELECT *

FROM locationRowT ASLTCROSS JOIN(SELECT row_id AS start_index FROM locationRowT WHERE level_code=SUBSTRING(@level_code,1,3)) ASLTRCROSS JOIN(SELECT row_id AS end_index FROM locationRowT WHERE level_code=@level_code) ASLTCWHERE LT.row_id BETWEEN LTR.start_index AND LTC.end_index

结果:

35c0d7b069becd0c901759647c593d98.png

2.7 获取某个节点的所有子节点

SELECT *

FROM Location2 ASLWHERE level_code LIKE '001%'

ORDER BY level_code

结果:

f1833df41fdc070a9a716216290add06.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值