数据库的树形结构
① 怎么往数据库里插入一个树形结构的表,并且用一句sql语句将其遍历出来
ID Value PID
0 根节点 null
1 节点1 0
2 节点2 0
3 节点3 1
..........
然后查询出来 再形成树就可以了
② 数据库中树形图的用法
数据库中树形图的用法的用法你知道吗?下面我就跟你们详细介绍下数据库中树形图的用法的用法,希望对你们有用。
数据库中树形图的用法的用法如下:
树形图用于显示按照树形结构进行组织的数据,其用途比较广泛,如计算机中的文件系统(Windows中的资源管理器)、企业或公司的组成结构等。我们知道在Windows下VB、PB、Delphi等工具提供了一个功能很强的树型控件TreeView,利用Treeview控件可以方便地开发树形图。然而在网页上实现树形图就不那么容易了,现在在asp.net中利用微软提供的Internet Explorer WebControls它使得网页上的树形图开发与在Windows下一样的方便,一样的功能强大,甚至更灵活。
本文介绍用Internet Explorer WebControls开发树形图的方法,由于树形图结构较复杂,使用起来常不知如何下手。笔者结合最近刚为公司用ASP.NET编写的应用程序管理器这一具体实例,详细阐述在ASP.NET下如何将Internet Explorer WebControls的使用与数据库联系起来,实现数据分任意多层显示,方便地进行增加、修改、删除、移动操作。笔者希望通过对该实例的阐述,达到抛砖引玉的效果,与各位同仁相互交流,共同进步。
Internet Explorer WebControls不在VS.NET的标准Server Control中,要到微软的站点上下载,下载地址是:
http://msdn.microsoft.com/downloads/samples/internet/default.asp?url=/Downloads/samples/Internet/ASP_DOT_NET_ServerControls/WebControls/default.asp
下载安装后第一次使用时,要右击工具箱Customize Toolbox…→.NET Framework Components中找到Micosoft.Web.UI.WebControls.Treeview后选中,这样Treeview控件就出现在工具箱中了。
一、树的建立
具体方法是:创建一个数据库,设计树图信息表TREE_INFO,包含NODEID、PARENTID、NODENAME、ADDErss、ICON字段,其它字段根据实际业务而定,节点名称NODENAME将在树型控件的节点上显示,NODEID字段保存节点的唯一标识号,PARENTID表示当前节点的父节点号,标识号组成了一个“链表”,记录了树上节点的结构。设计一个Web窗体其上放置TreeView控件。
PRivate Sub CreateDataSet()’建立数据集
Dim myConn As New SqlConnection()
Dim myCmd As New SqlCommand("select NODEID,NODENAME,PARENTID,ADDRESS,ICON from Tree_info", myConn)
Dim myDataAdapter As New SqlDataAdapter()
myConn.ConnectionString = application("connectstring")
myCmd.CommandText = ""
myCmd.Connection = myConn
myDataAdapter.SelectCommand = myCmd
myDataAdapter.Fill(ds, "tree")
End Sub
建树的基本思路是:从根节点开始递归调用显示子树
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
CreateDataSet()
intiTree(TreeView1.Nodes, 0)
End Sub
Private Sub intiTree(ByRef Nds As TreeNodeCollection, ByVal parentId As Integer)
Dim dv As New DataView()
Dim drv As DataRowView
Dim tmpNd As TreeNode
Dim intId As Integer
dv.Table = ds.Tables("tree")
dv.RowFilter = "PARENTID=’" & parentId & "’"
For Each drv In dv
tmpNd = New TreeNode()
strId = drv("NODE_ID")
tmpNd.ID = strId
tmpNd.Text = drv("NODE_NAME ")
tmpNd.ImageUrl = drv("ICON").ToString
Nds.Add(tmpNd)
intiTree(Nds(Nds.Count - 1).Nodes, intId)
Next
End Sub
二、增加、删除树节点
单纯在Treeview 上增加、删除、修改节点只需用Nodes属性的Add、 Remove、等方法即可,值得注意的地方是VS.NET中Treeview的Nodes集合与VS6.0中的区别,VS6.0中的是一个大的集合,而VS.NET中的是分层的每个Node下都有Nodes属性。增加、删除、修改树节点时与VS6.0相比有很大差别,特别是删除时。
Private Sub ButAdd_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButAdd.Click’在选定的节点下添加子节点
Dim tmpNd As New TreeNode(), NdSel As TreeNode
tmpNd.ID = GetNewId()
NdSel = TreeView1.GetNodeFromIndex(TreeView1.SelectedNodeIndex)’选中的节点
tmpNd.Text = "新节点"
NdSel.Nodes.Add(tmpNd)
Dim myRow As DataRow
myRow = ds.Tables("tree").NewRow()
myRow("NODE_NAME") = tmpNd.ID
myRow("NODE_DESCRipT") = "新节点" & tmpNd.ID & "_" & NdSel.ID
myRow("PARENT_NAME") = NdSel.ID
ds.Tables("tree").Rows.Add(myRow)
End Sub
Private Sub ButDele_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles ButDele.Click’删除选中的节点
Dim idx As String = TreeView1.SelectedNodeIndex()
GetNdCol(idx).Remove(TreeView1.GetNodeFromIndex(idx))
Dim dv As New DataView(), recNo As Integer
dv.Table = ds.Tables("tree")
dv.RowFilter= "NODEID=" & NdId
dv.Delete(0)
End Sub
Private Function GetNdCol(ByVal idx As String) As TreeNodeCollection
‘获得选中节点的父节点的Nodes集合
Dim cnt As Integer, i As Integer
Dim tmpNds As TreeNodeCollection
Dim idxs() As String
idxs = Split(idx, ".")
cnt = UBound(idxs)
If cnt = 0 Then
tmpNds = TreeView1.Nodes
Else
tmpNds = TreeView1.Nodes(CInt(idxs(0))).Nodes
For i = 1 To cnt - 1
tmpNds = tmpNds(CInt(idxs(i))).Nodes
Next
End If
Return tmpNds
End Function
三、修改、移动树节点
由于服务器控件不支持鼠标拖动事件,所以不能象Windows程序那样通过拖动移动节点,这里是通过选择父节点的方式。移动是通过在原位置删除,新位置添加实现的,要注意在删除时先保存节点信息。
Private Sub TreeView1_SelectedIndexChange(ByVal sender As Object, ByVal e As Microsoft.Web.UI.WebControls.TreeViewSelectEventArgs) Handles TreeView1.SelectedIndexChange
Dim dv As New DataView()
dv.Table = ds.Tables("tree")
Dim tmpNd As TreeNode = TreeNdSel(e.OldNode), tmpNds As TreeNodeCollection
dv.RowFilter= "NODEID=" & tmpNd.ID
dv(0)("NODE_DESCRIPT") = Me.TextBox1.Text
dv(0)("ADDRESS") = Me.TextBox2.Text
dv(0)("TARGET") = Me.TextBox3.Text
dv(0)("ICON") = Me.TextBox4.Text
If dv(0)("PARENTID").ToString <> Me.DropDownList1.SelectedItem.Value Then
‘移动节点
dv(0)("PARENT_NAME") = Me.DropDownList1.SelectedItem.Value
If Me.DropDownList1.SelectedItem.Value = "ROOT" Then
tmpNds = TreeView1.Nodes
Else
tmpNds = FromIdToNode(Me.DropDownList1.SelectedItem.Value, TreeView1.Nodes).Nodes’新的父节点的Nodes集合
End If
GetNdCol(e.OldNode).Remove(tmpNd)
tmpNds.Add(tmpNd)
End If
tmpNd.Text = Me.TextBox1.Text
tmpNd.ImageUrl = Me.TextBox4.Text
tmpNd = TreeView1.GetNodeFromIndex(TreeView1.SelectedNodeIndex)
dv.RowFilter= "NODEID=" & tmpNd.ID
Me.TextBox1.Text = dv(0)("NODENAME").ToString
Me.TextBox2.Text = dv(0)("ADDRESS").ToString
Me.TextBox3.Text = dv(0)("TARGET").ToString
Me.TextBox4.Text = dv(0)("ICON").ToString
End Sub
Private Function FromIdToNode(ByVal ID As String, ByVal Nds As TreeNodeCollection) As TreeNode
‘由关键字查找节点
Dim i As Integer
Dim tmpNd As TreeNode, tmpNd1 As TreeNode
For Each tmpNd In Nds
If tmpNd.ID = ID Then
Return tmpNd
Exit Function
End If
tmpNd1 = FromIdToNode(ID, tmpNd.Nodes)
If Not (tmpNd1 Is Nothing) Then
Return tmpNd1
Exit Function
End If
Next
Return Nothing
End Function
③ java 递归数据库生成 树形结构问题
1、准备表结构及对应的表数据
a、表结构:
create table TB_TREE
(
CID NUMBER not null,
CNAME VARCHAR2(50),
PID NUMBER //父节点
)
b、表数据:
insert into tb_tree (CID, CNAME, PID) values (1, '中国', 0);
insert into tb_tree (CID, CNAME, PID) values (2, '北京市', 1);
insert into tb_tree (CID, CNAME, PID) values (3, '广东省', 1);
insert into tb_tree (CID, CNAME, PID) values (4, '上海市', 1);
insert into tb_tree (CID, CNAME, PID) values (5, '广州市', 3);
insert into tb_tree (CID, CNAME, PID) values (6, '深圳市', 3);
insert into tb_tree (CID, CNAME, PID) values (7, '海珠区', 5);
insert into tb_tree (CID, CNAME, PID) values (8, '天河区', 5);
insert into tb_tree (CID, CNAME, PID) values (9, '福田区', 6);
insert into tb_tree (CID, CNAME, PID) values (10, '南山区', 6);
insert into tb_tree (CID, CNAME, PID) values (11, '密云县', 2);
insert into tb_tree (CID, CNAME, PID) values (12, '浦东', 4);
2、TreeNode对象,对应tb_tree
public class TreeNode implements Serializable {
private Integer cid;
private String cname;
private Integer pid;
private List nodes = new ArrayList();
public TreeNode() {
}
//getter、setter省略
}
3、测试数据
public class TreeNodeTest {
@Test
public void loadTree() throws Exception{
System.out.println(JsonUtils.javaToJson(recursiveTree(1)));
}
/**
* 递归算法解析成树形结构
*
* @param cid
* @return
* @author jiqinlin
*/
public TreeNode recursiveTree(int cid) {
//根据cid获取节点对象(SELECT * FROM tb_tree t WHERE t.cid=?)
TreeNode node = personService.getreeNode(cid);
//查询cid下的所有子节点(SELECT * FROM tb_tree t WHERE t.pid=?)
List childTreeNodes = personService.queryTreeNode(cid);
//遍历子节点
for(TreeNode child : childTreeNodes){
TreeNode n = recursiveTree(child.getCid()); //递归
node.getNodes().add(n);
}
return node;
}
}
输出的json格式如下:
{
"cid": 1,
"nodes": [
{
"cid": 2,
"nodes": [
{
"cid": 11,
"nodes": [
],
"cname": "密云县",
"pid": 2
}
],
"cname": "北京市",
"pid": 1
},
{
"cid": 3,
"nodes": [
{
"cid": 5,
"nodes": [
{
"cid": 7,
"nodes": [
],
"cname": "海珠区",
"pid": 5
},
{
"cid": 8,
"nodes": [
],
"cname": "天河区",
"pid": 5
}
],
"cname": "广州市",
"pid": 3
},
{
"cid": 6,
"nodes": [
{
"cid": 9,
"nodes": [
],
"cname": "福田区",
"pid": 6
},
{
"cid": 10,
"nodes": [
],
"cname": "南山区",
"pid": 6
}
],
"cname": "深圳市",
"pid": 3
}
],
"cname": "广东省",
"pid": 1
},
{
"cid": 4,
"nodes": [
{
"cid": 12,
"nodes": [
],
"cname": "浦东",
"pid": 4
}
],
"cname": "上海市",
"pid": 1
}
],
"cname": "中国",
"pid": 0
}
④ 树形数据库有哪些
树形数据库介绍与特征:
关系数据库中BOM结构是树状的,但是速度不怎么样。
理想中树形结构应该具备如下特征:
数据存储冗余度小、直观性强;
检索遍历过程简单高效;
节点增删改查CRUD操作高效。
⑤ 如何在关系型数据库中存储树形结构
文中使用公司部门结构树作为栗子,要在mysql中存储这个公司部门结构树
邻接表想必大家都不陌生吧,用邻接表的关键是,在每个节点存储他的父节点的id。
在每一个部门信息中都存储了他的父节点id,parent_id字段
导入数据的过程就不说了,直接来看下数据吧:
这里使用常用的几种查询方式来看下这种方案的查询
可以通过parent_id做查询条件,可以快速查询到一个部门的直属下级部门
通过部门信息中的parent_id去查相应的父节点信息就可以快速实现
这种数据存储结构下,更新数据是比较方便快捷的,添加数据时直接找准父节点的id,组织部门变更时,也直接变更父id就好了,删除时候,看自己业务是否需要删除子节点这几种情况,
路径标的要点,就是每个节点存储根节点到该节点的路径,其实我觉得和别的几种方案可以共用
在每一个部门信息中都存储了他完整的路径,path字段
导入数据的过程就不说了,直接来看下数据吧:
使用路径表,通过path这个字段查询起来是比较困难的,一般都需要使用like,CONCAT函数、REPLACE函数等做字符串的处理逻辑,查询起来比较复杂,这里不做展示了,线上服务不建议使用这种方式,查询效率低会影响到服务性能,一般建议和邻接表方式统一使用,同时添加parent_id和path字段,parent_id用来查询,path用来查看节点完整的路径
这种数据存储结构下,更新数据是比较方便快捷的,添加数据时直接找准路径就好,组织部门变更时,也直接找准路径就好,删除时候,看自己业务是否需要删除子节点这几种情况,
Closure Table,网络直译过来叫闭合表,大多数人叫做闭包表,这种方案的要点是存储公司部门信息主表中,不存储节点关系的数据,使用另一张关系表来存储节点之间的关系,其中包含了任何两个有关系(上下级)节点的关联信息
公司部门信息主表,只需要存储部门的本身信息
主要包括三个字段
要点就是关系表的一条记录是一个上级节点、下级节点、与他们之间的路径距离。拿部门结构图来举例子
总公司-企划部的关系数据是:
总公司-大区A的关系数据是:
关系表中存储所有的节点路径信息,还用distance表示路径的距离,需要把树形结构中每两个节点之间的路径信息都维护进来。
数据存储的过程就拿导入总公司-门店A的过程做个示例。主表的数据存储就不说,说下关系中,存储部门结构的路径信息,总公司-门店A总共包含以下几条路径:
看到了么,是存储了所有总公司-门店A之间的路径信息
这里使用常用的几种查询方式来看下这种方案的查询
这种数据存储结构下,更新数据比较麻烦,因为他存储了两节点直接所有路径信息(包括中间节点的)