树型数据库求和的问题 (300分)

  • 主题发起人 主题发起人 ugvanxk
  • 开始时间 开始时间
U

ugvanxk

Unregistered / Unconfirmed
GUEST, unregistred user!
id pid value kind
0 -1 0
1 0 1
2 0 1
3 0 1
4 1 1
5 2 2
6 3 2
7 4 2
8 4 2
9 1 2
10 1 2
建立一棵树,加的字节点可能 kind=1 或kind=2 ,
当kind=0 或kind=1 时,value的值都没有,只有kind=2即叶节点的情况才有值。
即kind=2 不可能再有字节点
然后要把上一级的 kind=1的赋值, 最后求出 kind=0的值,即最高的节点的值。
考虑添加 删除 修改的情况
用存储过程,或触发器,程序也可以
 
我建立了触发器,然后选择了可以递规调用
create trigger trg_delete
on tablename
for delete
as
delete from tablename where pid in(select id from deleted)
执行
delete from tablename where id=0//1
提示嵌套超过32级,没有执行。



 
pid value 是一个字段吗,如果不是,那么你的value没有一个有值,
如果是,则kind=0,1,2都有值
你的意思没有表达清楚
 
既然是树,最好的办法就是用递归了,有关树的算法,《数据结构》中讲得很清楚
 
问题是按层求和,可在KIND字段编写代码,象会计科目编码一样,3-2-2 ,
select substr(kind,1,3) as king,sum(x) as x from table1 group by king
union all
select substr(kind,1,5) as king,sum(x) as x from table1 group by king

上述语句在VFP中可以实现,在其他数据管理体统时,语句可能不一样
 
value是要输入值,在程序里用递规算法已经实现,不知存储过程怎么实现
function TForm1.AddTree(Id: Integer): integer;
//£½1±éÀúËùÓÐ×ӽڵ㣬¿ÉÒÔ¸üжà¸öµØ·½£¬È»ºóÔÙ¼ÆËã
var
myQuery:TQuery;
iId:Integer;
tempValue:Integer;
const
SQLStr='select id from systemtree where pid=%d';
SQLStr1='update systemtree set arg=%d where id=%d';
SQLStr2='select arg from systemtree where id=%d';
begin
tempValue:=0;
myQuery:=TQuery.Create(Self);
try
myQuery.DatabaseName:='aaa';
myQuery.SQL.Add(Format(SQLStr,[id]));
myQuery.Open;
while not myQuery.Eof do
begin
iId:=myQuery.FieldByName('id').AsInteger;
tempValue:=tempValue+AddTree(iId);
myQuery.Next;
end;
myQuery.Close;
If tempValue<>0 Then
begin
myQuery.Sql.Clear;
myQuery.Sql.Add(Format(SQLStr1,[tempValue,id]));
myQuery.ExecSQL;
Result:=tempValue;
end
else begin
myQuery.Sql.Clear;
myQuery.Sql.Add(Format(SQLStr2,[id]));
myQuery.Open;
Result:=myQuery.FieldByName('arg').AsInteger;
myQuery.Close;
end;
finally
myQuery.Free;
end;
end;

procedure TForm1.BitBtn1Click(Sender: TObject);
begin
Query1.Close;
Query1.Open;
end;

procedure TForm1.BitBtn2Click(Sender: TObject);
begin
AddTree(1);
end;

procedure TForm1.UpdateTree(PID: Integer);
//&amp;Ouml;&amp;raquo;&amp;Ecirc;&amp;Ccedil;&amp;cedil;ü&amp;ETH;&amp;Acirc;&amp;Ograve;&amp;raquo;&amp;Igrave;&amp;otilde;&amp;frac14;&amp;Ccedil;&amp;Acirc;&amp;frac14;&amp;micro;&amp;Auml;&amp;Ccedil;é&amp;iquest;&amp;ouml;
const
SQLStr='select arg from systemtree where pid=%d';
SQLStr1='update systemtree set arg=%d where id=%d';
SQLStr2='select pid from systemtree where id=%d';
var
myQuery:TQuery;
tempValue:Integer;
begin
tempValue:=0;
myQuery:=TQuery.Create(self);
try
myQuery.DatabaseName:='aaa';
myQuery.SQL.Add(Format(SQLStr,[PID]));
myQuery.Open;
while not myQuery.Eof do
begin
tempValue:=tempValue+myQuery.FieldByName('arg').AsInteger;
myQuery.Next;
end;
myQuery.Close;
myQuery.SQL.Add(Format(SQLStr1,[tempValue,PID]));
myQuery.ExecSQL;

myQuery.SQL.Clear;
myQuery.SQL.Add(Format(SQLStr2,[PID]));
myQuery.Open;
If not myQuery.Eof Then
begin
UpdateTree(myQuery.FieldByName('pid').AsInteger);
end;
myQuery.Close;
finally
myQuery.Free;
end;
end;

procedure TForm1.BitBtn3Click(Sender: TObject);
begin
UpdateTree(6);
end;

procedure TForm1.CreateTree(ID: Integer; Node: TTreeNode);
//&amp;para;&amp;macr;&amp;Igrave;&amp;not;&amp;acute;&amp;acute;&amp;frac12;¨&amp;Ecirc;÷
var
iPartID:Integer;
TreeNode: TTreeNode;
myQuery:TQuery;
const
SQLStr1='select * from systemtree where pid=%d';
begin
myQuery:=TQuery.Create(Self);
try
with myQuery do
begin
DatabaseName:='aaa';
SQL.Add(Format(SQLStr1,[Id]));
Open;
while not Eof do
begin
iPartID:=FieldByName('id').AsInteger;
TreeNode:=tvTree.Items.AddChild(Node,FieldByName('id').Asstring);
TreeNode.StateIndex:=iPartID;
CreateTree(iPartID,TreeNode);
Next;
end;
Close;
end;
finally
myQuery.Free;
end;
end;

procedure TForm1.BitBtn4Click(Sender: TObject);
begin
tvTree.Items.Clear;
CreateTree(1,nil);
end;

procedure TForm1.DeleteTree(Id: Integer);
//&amp;Eacute;&amp;frac34;&amp;sup3;&amp;yacute;&amp;Egrave;&amp;Icirc;&amp;Ograve;&amp;raquo;&amp;frac14;&amp;para;±&amp;eth;
var
myQuery:TQuery;
iPId:Integer;
const
SQLStr='select id from systemtree where pid=%d';
SQLStr1='delete from systemtree where id=%d';
begin
iPId:=Id;
myQuery:=TQuery.Create(Self);
try
myQuery.DatabaseName:='aaa';
myQuery.SQL.Add(Format(SQLStr,[id]));
myQuery.Open;
while not myQuery.Eof do
begin
iPId:=myQuery.FieldByName('id').AsInteger;
DeleteTree(iPId);
myQuery.Next;
end;
myQuery.Close;
myQuery.SQL.Clear;
myQuery.SQL.Add(Format(SQLStr1,[id]));
myQuery.ExecSQL;
finally
myQuery.Free;
end;
end;

procedure TForm1.BitBtn5Click(Sender: TObject);
begin
DeleteTree(Query1.FieldByName('id').AsInteger);
end;
 
既然可以建立一棵树,就可以在建树时来进行计算。
 
请教一下这种存储过程有没有递规的,怎么写。
递规触发器应该怎么写。
 
怎么这个问题还没有解决么?
没有人回答么?
我倒是找了一个类似的解决方案,不过存在一些问题。
交流一下
 
我正在用递规的存储过程做,如果解决我会贴上源码
我的e-mail jsqmail◎163.com
 
等你的好消息。
 
没有数据,没有经过测试,到时候再测试,先提提意见
CREATE PROCEDURE PROC_PRODUCTRATE
@ID INT,--产品对应的自编编号
@ENID INT,--环境自增编号
@SOURCEID INT--数据源 GJB299B或美军标
--@PRODUCT_RATE FLOAT --返回产品的失效率
AS
DECLARE
@ATTR INT, --0输入值 1--自动计算值
@KIND INT, --0系统 1-组件 2-元器件
@IID INT, --对应的自增编号
@SUBID INT,--元器件对应的自增编号
@BASERATE DECIMAL(10,3), --基本失效率
@NUM INT, --元器件数目
@TOTALRATE DECIMAL(10,3), --总失效率
@COUNT INT, --门数,位数
@QXS FLOAT, --质量系数,直接得出数值
@G FLOAT,--通用失效率
@RATE FLOAT,--失效率
@TEMPVALUE FLOAT,--临时变量
@VALUE FLOAT


SET @VALUE=NULL
--参数id为不存在的情况
--IF (@ID IS NULL )or(@ENID IS NULL)OR(@SOURCEID IS NULL) RETURN 0
SELECT * FROM TABLERELATION WHERE ID=@ID
--如果没有一条记录
IF @@ROWCOUNT=0
RETURN 0

--不需要计算的情况,直接写入的数据,可能为组件级别,也可能为元器件级别
SELECT @NUM=ISNULL(QUANTITY,1),@TOTALRATE=ISNULL(TOTALFAILURERATE,0),@SUBID=SUBKIND,
@QXS=ISNULL(QUALITY,0),@COUNT=ISNULL(DIGIT,0),@KIND=ISNULL(GRADE,2),@BASERATE=BASFAILURERATE
FROM TABLERELATION WHERE ID=@ID and FAILUREATTR=1
RETURN @TOTALRATE

--定义游标选出所有子节点
DECLARE CUR_PARENT CURSOR FOR
SELECT ID--, BASFAILURERATE,QUANTITY,TOTALFAILURERATE,FAILUREATTR,QUALITY,GRADE,SUBKIND
FROM TABLERELATION WHERE PID=@ID

--打开游标,选取第一条
OPEN CUR_PARENT
FETCH NEXT FROM CUR_PARENT INTO @IID--,@BASERATE,@NUM,@TOTALRATE,@ATTR,@QXS,@KIND,@SUBID
IF @@FETCH_STATUS<>0
BEGIN
RAISERROR 50002 '打开游标错误'
return -10
END

--循环查找子节点
WHILE @@FETCH_STATUS<>-1
BEGIN
--如果还有子节点,递规调用
IF (@@FETCH_STATUS<>-2)
BEGIN
EXEC @TEMPVALUE=PROC_PRODUCTRATE @IID,@ENID,@SOURCEID--,@PRODUCT_RATE
SET @VALUE=@VALUE+@TEMPVALUE
END

--取下一条记录
FETCH NEXT FROM CUR_PARENT INTO @IID--,@BASERATE,@NUM,@TOTALRATE,@ATTR,@QXS,@KIND,@SUBID
END

--关闭游标,释放游标
CLOSE CUR_PARENT
DEALLOCATE CUR_PARENT

IF @VALUE IS NOT NULL
BEGIN
--更新对应的产品数据库的组件和系统部分
UPDATE TABLERELATION
SET BASFAILURERATE= @VALUE,
TOTALFAILURERATE=@VALUE*ISNULL(QUANTITY,1)
FROM TABLERELATION WHERE ID=@ID
SET @VALUE=@VALUE*(SELECT ISNULL( QUANTITY,1) FROM TABLERELATION WHERE ID=@ID)
RETURN @VALUE
END
ELSE BEGIN
--取出对应的属性0--输入1--自动计算,数量,累计故障率,对应的元器件编号,质量系数,门数,级别,故障率
SELECT @ATTR=ISNULL(FAILUREATTR,1),@NUM=ISNULL(QUANTITY,1),@TOTALRATE=ISNULL(TOTALFAILURERATE,0),@SUBID=SUBKIND,
@QXS=ISNULL(QUALITY,0),@COUNT=ISNULL(DIGIT,0),@KIND=ISNULL(GRADE,2),@BASERATE=BASFAILURERATE
FROM TABLERELATION WHERE ID=@ID
IF @ATTR=0--如果是输入的值
RETURN @TOTALRATE
ELSE BEGIN
--通过查表求出通用失效率
SET @G=(SELECT FRATE_G FROM TABLEFAILURERATE WHERE SUBKINDID=@SUBID AND
ENID=@ENID AND DATASOURCEID=@SOURCEID AND @COUNT>= ISNULL(MINCOUNT,0)
AND @COUNT<=ISNULL(MAXCOUNT,0))
SET @RATE=ISNULL(@QXS*@G,0)
--如果不是元器件,但又是最后一级,因为计算结果肯定为0,保留原来的数值
IF (@BASERATE>0)AND(@RATE=0) --AND(@KIND<>2 ) 不管组件还是元器件如果为0都保留原来的值
BEGIN
SET @RATE=@BASERATE
END
--更新对应的产品数据库的元器件/组件部分--最后一层节点
UPDATE TABLERELATION
SET BASFAILURERATE=@RATE,
@TOTALRATE=TOTALFAILURERATE=(@RATE*@NUM)
WHERE ID=@ID
RETURN @TOTALRATE
END
END
GO
 
OnlyP 父项
OnlyC 子项


procedure TE0008Frm.FormCreate(Sender: TObject);
var
Node, Item: TdxTreeListNode;
begin
tvlTree.BeginUpdate;
tvlTree.ClearNodes;
EfSetQueryOpen(EfqryHelp, 'SELECT OnlyP, OnlyC, Desci FROM KFlow ORDER BY OnlyC');
EfqryHelp.Filter := 'OnlyP = ' + QuotedStr('');
while not EfqryHelp.Eof do
begin
Node := tvlTree.Add;
Node.ImageIndex := 7;
Node.SelectedIndex := 9;
Node.Strings[0] := EfqryHelp['Desci'];
Node.Strings[1] := EfqryHelp['OnlyC'];
EfqryHelp.Next;
end;

Node := tvlTree.TopNode; while Node <> nil do
begin
EfqryHelp.Filter := 'OnlyP = ' + QuotedStr(Node.Strings[1]);
while not EfqryHelp.Eof do
begin
Item := Node.AddChild;
Item.ImageIndex := 7;
Item.SelectedIndex := 9;
Item.Strings[0] := EfqryHelp['Desci']; Item.Strings[1] := EfqryHelp['OnlyC']; EfqryHelp.Next;
end;
Node := Node.GetNext;
end;

 
[:D][:D]
哈哈,还是我露一手吧,大家不要笑话就行:

假设你的表名是TABLE
update A set A.value = B.SUMVALUE FROM
TABLE A INNER JOIN (SELECT PID, SUM(VALUE) AS SUMVALUE FROM TABLE WHERE KIND = 2 GROUP BY pid ) B
ON A.ID = B.PID

update A set A.value = B.SUMVALUE FROM
TABLE A INNER JOIN (SELECT PID, SUM(VALUE) AS SUMVALUE FROM TABLE WHERE KIND = 1 GROUP BY pid ) B
ON A.ID = B.PID

错别字嘛,很难免(太多次了);思路嘛,如果不对,我提头来见!
——说清楚,不一定是我的头啊。[:D][:D]
 
定义的存储过程里的游标总是提示重复定义或已经定义过
应该怎么解决,释放掉后再定义肯定是有的超过一条的就取不出来
 
有没有包含游标的递规的例子,发到上面,或可能不可能实现,怎么实现
解答出来单独给分300分
 
kind =1 的节点的值
select sum(value) from table where pid=theId and kind=2

kind=0 的节点的值
如果只有一个 0 节点
select sum(value) from table where kind=2
如果有多个
select sum(value) from table a where kind=2 and
exists (select pd from table b where b.pid=theId0 and a.pid=b.id)
 
是这样的有n层,每层计算完,要汇总到上层,你这样估计不行,最后汇总到最高层
 
To 楼主:
>>建立一棵树,加的字节点可能 kind=1 或kind=2
这是你说的吧,正因为只能是1或2,所以才可以那么简单的解决,如果是无限制的层次,
当然还有更好的办法了,不过,不告诉你![:D][:D][:D]
 
后退
顶部