需要实现如下效果:
从数据库中提取数据,结构如下
编码 名称
01 a1
0101 a11
010101 a111
010102 a112
0102 a12
010201 a121
02 a2
0201 a21
020101 a211
。
想实现如下的树
---A
|---a1
| |---a11
| | |--a111
| | .........
| |---a12
| .........
|----a2
......................
请问,应该如何解决?
新手,希望得到帮助。
从数据库中提取数据,结构如下
编码 名称
01 a1
0101 a11
010101 a111
010102 a112
0102 a12
010201 a121
02 a2
0201 a21
020101 a211
。
想实现如下的树
---A
|---a1
| |---a11
| | |--a111
| | .........
| |---a12
| .........
|----a2
......................
请问,应该如何解决?
新手,希望得到帮助。
解决方案 »
- TdxNavBar 用法
- 下载,断点续传
- ◆◆每年新增大概2万张图片,用Access数据库可行吗?◆◆
- 如何屏蔽除主程序外的其他程序?
- 高手参与---如何自动监测 CreateObject() 事件?
- 非常自责,散分!
- 没分了, 还请教小弟一个问题...
- INDY10里如何使用带SSL的TIdHttpServer,INDY9的调用不适合在INDY10
- Access Violation address 40003ABF in module "VCL50.BPL",read of address FFFFFFFF 是什么错误?
- 菜鸟第一问:(我K,这样的语句都会有错!)怎么回事?
- 这个SQl怎么写
- 怎么做类似于windows资源管理器窗口中可以左右拖动的效果?
问题
父 子 值
A B 1
B C 1
B D 2
D E 3
-------------------
A
B(1)
C(1) D(2)
E(3)
A有 1 个B,B有 2 个D,D有 3 个E
我想算出A有几个E,几个D ,几个B解决方法
--测试--测试数据
create table 表(父 char(1),子 char(1),值 int)
insert 表 select 'A','B',1
union all select 'B','C',1
union all select 'B','D',2
union all select 'D','E',3
go--存储过程
create proc p_calc
@id char(1)='A', --要查询的节点
@num int=1 --数量
as
declare @l int
set @l=0
create table #re(id char(1),level int,num int)
insert #re select @id,@l,@num
while @@rowcount>0
begin
set @l=@l+1
insert #re select a.子,@l,num=b.num*a.值
from 表 a join #re b on a.父=b.id
where b.level=@l-1
end
select id,num=sum(num) from #re group by id
go
--调用查询
exec p_calc
go
/*--测试结果
id num
---- -----------
A 1
B 1
C 1
D 2
E 6(所影响的行数为 5 行)
--*/
create table t_test(编码 varchar(20),名称 varchar(20))
--插入数据
insert into t_test
select '01', 'a1'
union select '0101', 'a11'
union select '010101', 'a111'
union select '010102', 'a112'
union select '0102', 'a12'
union select '010201', 'a121'
union select '02', 'a2'
union select '0201', 'a21'
union select '020101', 'a211'
union select '020102', 'a212'
union select '02010101', 'a2111'
union select '0201010101', 'a21111'//delphi程序实现
//窗体上放 button1,adoconnection1, ADOquery1,TreeView1
//ADOquery1的connection连接 adoconnection1
//button1的点击事件里写
procedure TForm1.Button1Click(Sender: TObject);
function MakeTree:Boolean;
var
nodeCur:TTreeNode;
sPrt,sCld:String;
iNodeLenth:Longint;
begin
nodeCur:=nil;
with ADOquery1 do
try
Close;
sql.Clear;
sql.add('select * from t_test order by 编码');
Open;
First;
while not eof do
begin
sPrt:=FieldByName('编码').AsString;
sCld:=FieldByName('名称').AsString;
if Length(sPrt)=2 then
begin
nodeCur:=TreeView1.Items.AddChild(TreeView1.GetNodeAt(0,0),sCld);
nodeCur.StateIndex:=StrToInt(sPrt);
end
else
begin
while nodeCur.StateIndex<>strtoint(copy(sPrt,1,length(sPrt)-2)) do
nodeCur:=nodeCur.Parent;
nodeCur:=TreeView1.Items.AddChild(nodeCur,sCld);
nodeCur.StateIndex:=strtoint(sPrt);
end;
Next;
end;
except
showmessage('出错!');
raise;
end;
result:= true;
end;
begin
TreeView1.Items.Clear;
TreeView1.Items.BeginUpdate;
TreeView1.Items.AddChild(nil,'A');
MakeTree;
TreeView1.Items.EndUpdate ;
TreeView1.FullExpand;
end;
谢谢大家,解决就给分
var node:TTreeNode;
begin
node:=nil;
with ADOQuery1 do
begin
Close;
Sql.Text:='SELECT * FROM t ORDER BY 编码';
Open;
TreeView1.Items.BeginUpdate;
First;
try
while not Eof do
begin
Node:=TreeView1.Items.AddChildObject(Node,FieldByName('名称').AsString,Pointer(FieldByName('编码').Asstring));
Next;
while (node<>nil) and (Length(FieldByName('编码').AsString)<=Length(string(Node.Data))) do
node:=node.Parent;
end;
finally
TreeView1.Items.EndUpdate;
end;
TreeView1.FullExpand;
end;
end;
但是如果数据量大的话,采用上面的速度将很慢,
因此建议动态的生成树,在TTreeView的OnExpanded生成子节点,
在TTreeView的在OnCollapsed
这样程序性能要提高
有一个TdxDBTreeView,可以直接连到数据库的表,设置几个参数就可以把表中的数据取出生成树了。
procedure tfrm1.refreshTree;
var
level0,level1,level2:Ttreenode;
id,name:string;
begin
infoTree.Items.Clear;
dm_main.ADST_D.Close;
dm_main.ADST_D.CommandText :='select * from infrm';
dm_main.ADST_D.Open;
level0:=infoTree.Items.Add(infotree.TopItem,'列表');
level0.DeleteChildren ;
try
dm_main.ADST_d.IndexFieldNames :='ID';//这句很重要,如果你没设主键,
//这里首先按编码排一下序,再一条条读
dm_main.ADST_d.Open ;
dm_main.ADST_d.First;
while not dm_main.ADST_d.Eof do
begin
id:=trim(dm_main.ADST_dID.AsString);
name:=trim(dm_main.ADST_dName.asstring);
//添加第一级
if length(trim(id))=2 then
level1:=infotree.Items.AddChild(level0,'('+id+')'+name);
//添加第二级
if length(trim(id))=4 then
level2:=infotree.Items.AddChild(level1,'('+id+')'+name);
dm_main.ADST_d.next;
end;
except
showmessage('asdasdfsdfsdf');
end;
dm_main.ADST_d.close;
level0.Expand(false);
end;
如果大家感到分数不够,我可以另外开帖补足分数。
另 huamanlouzcj() ,能否详细说明一下,偶不是很明白。
另存储过程的最后一句改为以下:
select id,level,num=sum(num) from #re group by id,level
这样不就可以了吗?
以上是一次读取其全部BOM的展开树,
如果数据量很大,则可以在treeview的oncustomdrawitem事件中写。一次只读一层。
不用递归算法啊!
分为两张表,其中一张表用来储存基本代码表,另外一张表用来表示其隶属关系。如下 :
表1 表2
编码 名称 子 父
01 a1 02 01
02 a2 03 01
03 a3 04 01
04 a4 05 02
05 a5其树如下:
--a1
|--a2
|--a5
|--a3
|--a4
然后再利用我上面提到的思路!这样可以不受编码长度的限制!