假设三层(多一层加多一个update):update a
set Amount=(select sum(Amount) from tablename where name like rtrim(a.name)+'-_____')
from tablename a
where name like '_____-_____'update a
set Amount=(select sum(Amount) from tablename where name like rtrim(a.name)+'-_____')
from tablename a
where name like '_____'
set Amount=(select sum(Amount) from tablename where name like rtrim(a.name)+'-_____')
from tablename a
where name like '_____-_____'update a
set Amount=(select sum(Amount) from tablename where name like rtrim(a.name)+'-_____')
from tablename a
where name like '_____'
我正在写,你就答复出来了,快!实在是快!
你的思路和我现在的差不多。如果是N层,则Update N-1次。
但是这种方法,我还觉得有点慢。我试过,如果有5层,1万条记录,肯定超过1分种。而且,如果5个用户并发操作,肯定死锁。
我正在写,你就答复出来了,快!实在是快!
你的思路和我现在的差不多。如果是N层,则Update N-1次。
但是这种方法,我还觉得有点慢。我试过,如果有5层,1万条记录,肯定超过1分种。而且,如果5个用户并发操作,肯定死锁。
还有没有更好的?
1.先把有子树的AMOUNT设为0
2.再用一句UPDATE
一句行吗?能讲详细些吗?
-------------------------
"再用一句UPDATE"。
-------------------------------------------------------------------
回复人: Yang_(扬帆破浪) ( ) 信誉:308 2002-09-25 16:48:00
记录数如果只有1万条左右,不用特别考虑速度。
再让父节点的AMOUNT为所有子孙节点AMOUNT的和
set Amount=(select sum(Amount) from table2 where left(name,length( rtrim(a.name)))=rtrim(a.name)
from table1 a思路:某一层次的name的amount是下面层次的amount之和。
复制另一相同表,是为了避免重复计算。
但是,我觉得可能大家没有仔细看我的提问。请注意:
1、假设Name中的层数是不定的,也就是说如果按照(扬帆破浪)的思路,在UPDATE之前还有一段计算层数的时间。请考虑每次计算层数所消耗的时间,下面是我的代码:
CREATE Function GetItemNumberTierCount
(@ItemNumber Varchar(25))
RETURNS Tinyint
AS
BEGIN
DECLARE @TierCount Tinyint --存放返回值
DECLARE @Position Tinyint SET @Position=1
SET @TierCount=1
WHILE @Position<=Len(@ItemNumber)
BEGIN
IF Left(@ItemNumber,@Position) Like '%-'
BEGIN
SET @TierCount=@TierCount+1
END
SET @Position=@Position+1
END RETURN @TierCount
END
GOselect GetItemNumberTierCount(max(len(name))) from table12、表中的记录数超过1万条,而且实际应用中还有汇总后列与列之间的计算。
例如:Quantity需要先分层汇总,然后Amount=Quantity*Price。所以我目前的提问只是一个算法模型,所以要求在超过1万条的情况下(内存:1024kb~190mb,tmpdb:20M),计算时间至少<1Second我目前用的算法和 Yang_(扬帆破浪)最先说的一样,但是速度不太理想。希望大家继续提出宝贵意见!
select max(len(name))/5 from table1
update t3 set amount=t5.amount
from tree t3,(
select t0.id,sum(isnull(t1.amount,0)) as amount
from tree t0,tree t1
where left(t1.name,len(t0.name))=t0.name and not exists(select parentid from tree t2 where t2.parentid=t1.id)
group by t0.id) t5
where t3.id=t5.id and exists (select parentid from tree t4 where t4.parentid=t3.id)
fhaschild--是否有子节点
flevel--是第几层
这样在做类似统计时对效率有很大的好处。只是在新增修改时算法会麻烦一点。
如果有这两个字段,上面的语句会简化些,且效率高很多。
create proc Pr_ChangeAmount
as
declare @index int
set @index=0
select @index=max(len(name))/5-1 from tbltest
declare @name varchar(30)
while @index>0
begin
set @Name=REPLICATE ('_____-',@Index)
set @Name=left(@Name,len(@Name)-1)
select @Name
update a
set Amount=isnull((select sum(Amount) from tbltest where name like rtrim(a.name)+'-_____'),Amount)
from tbltest a
where name like @name
set @index=@index-1
end
go
即然用了循环了,干嘛不用,先清零再一句出来?
清零要判断是不是叶子结点,叶子结点不能清,否则就丢是数据了。
我不知道怎么写一条语句!
如果没有ParentID=当前ID的,就是末节点,就可清0
create table t3 (ID int,Name varchar(20),Amount decimal(10,4),ParentID int)
insert t3 select 1, '00001', null, Null
union all select 12, '00004-00002' ,null, 10
union all select 13, '00004-00002-00001' ,0.1, 12
union all select 2, '00001-00001' ,60000, 1
union all select 7, '00003-00001-00001' ,1000, 6
union all select 8, '00003-00002' ,100, 5
union all select 9, '00003-00003' ,10, 5
union all select 10, '00004' ,null, Null
union all select 11, '00004-00001' ,1, 10
union all select 14, '00004-00002-00002' ,0.01, 12
union all select 15, '00004-00002-00003' ,0.001, 12
union all select 3, '00001-00002' ,40000, 1
union all select 4, '00002' ,10000, Null
union all select 5, '00003' ,null, Null
union all select 6, '00003-00001' ,null, 5
--上面打乱了update a set amount=0 from t3 a where exists(select 1 from t3 where ParentID=a.id)
--影响5行
update a set amount=(select sum(amount) from t3 where left(name,len(a.name)+1)=a.name+'-') from t3 a where exists(select 1 from t3 where ParentID=a.id)
--影响5行
select * from t3 order by id
:
ID Name Amount ParentID
----------- -------------------- ------------ -----------
1 00001 100000.0000 NULL
2 00001-00001 60000.0000 1
3 00001-00002 40000.0000 1
4 00002 10000.0000 NULL
5 00003 1110.0000 NULL
6 00003-00001 1000.0000 5
7 00003-00001-00001 1000.0000 6
8 00003-00002 100.0000 5
9 00003-00003 10.0000 5
10 00004 1.1110 NULL
11 00004-00001 1.0000 10
12 00004-00002 .1110 10
13 00004-00002-00001 .1000 12
14 00004-00002-00002 .0100 12
15 00004-00002-00003 .0010 12(所影响的行数为 15 行)没有错啊?
asupdate a
set Amount=0
from tbltest a
where exists (
select 1 from tbltest where ParentID=a.id
)update a
set Amount=(select sum(Amount) from tbltest where name like rtrim(a.name)+'-%')
from tbltest a
where exists (
select 1 from tbltest where ParentID=a.id
)
go
asupdate a
set Amount=0
from tbltest a
where exists (
select 1 from tbltest where ParentID=a.id
)update a
set Amount=(select sum(Amount) from tbltest where name like a.name+'-%')
from tbltest a
where exists (
select 1 from tbltest where ParentID=a.id
)
go
不过我还是觉得用触了器。每改变一次只修改其中一支。
语句跟上面一样,多加一个WHERE条件罢了。
这样如果记录多了用户多了,可能会好点。
To j9988:
为什么要先将父节点清零?不清零也可以的啊?如果是为了消除因聚合函数中出现空值而产生的警告,是不是可以用SET ANSI_WARNINGS OFF/ON ,这样更快?
To Yang_:
“触发器有分散统计的功能”具体是指什么意思?
为了便于讨论,我构造了该字段的值,其思想是来自于VB中TreeView的FullPathCode。在讨论中才发现,Name字段在汇总统计时竟然有意想不到的功效。
所以现在看来,处理类似问题,这张表应该为ID、PathCode、Name、Amount、ParentID。再问j8899:
假设表中只有ID、Amount、ParentID,能否一句Update?我想了很久,没想出!
Yang_(扬帆破浪) 44分 你第一个回答,而且实际做了不少测试。可惜你比j9988慢了一步...
j9988(j9988) 51分 特别的爱给特别的你,因为你最先解决了问题!
icevi(按钮工厂) 5分 中肯的建议,值得吸取,谢谢!-----------------------------------------------
--先问一问,这样给分,大家有没有意见?
-----------------------------------------------
触发器是在插入或者修改时计算,不必集中统计。
表中只有ID、Amount、ParentID,可以先把字节点id放到临时表,再update
怎么给分自己作主,不必看人家意见。
---------------------------
表中只有ID、Amount、ParentID,可以先把字节点id放到临时表,再update