【发布时间】:2014-07-07 14:43:04
【问题描述】:
我正在 SQL Server 2012 Express Edition SP1 上开发数据库。
我想对这两个存储过程进行递归:
Create procedure [dbo].[DisaggreagateChildren]
@parentCode nvarchar(20)
, @parentLevel tinyint
, @parentFlag tinyint
, @childrenFlag tinyint
as
begin
declare @aggregationId int
, @childCode nvarchar(20)
, @childLevel tinyint;
declare @tempChilds table (
Code nvarchar(20),
CodeLevel tinyint)
[ ... ]
set rowcount 1
select @childCode = code, @childLevel = CodeLevel from @tempChilds
-- Loop all child codes.
while @@rowcount <> 0
begin
-- Get first code and delete it from temporary table.
set rowcount 0
select * from @tempChilds where code = @childCode and CodeLevel = @childLevel;
delete @tempChilds where code = @childCode and CodeLevel = @childLevel;
if (@childLevel = 1)
update dbo.CODES
set COMMISIONING_FLAG = @childrenFlag
where ID_CODE = @childCode and CODE_LEVEL = @childLevel;
else
begin
update dbo.CODES
set COMMISIONING_FLAG = @parentFlag
where ID_CODE = @childCode and CODE_LEVEL = @childLevel;
-- Recursive call to disaggregate @childCode's childrens.
EXEC dbo.DisaggreagateChildren @childCode, @childLevel, @parentFlag, @childrenFlag
end
-- Get next code.
set rowcount 1
select @childCode = code, @childLevel = CodeLevel from @tempChilds
end -- while end
set rowcount 0
end -- Procedure end.
go
Create procedure [dbo].[Disaggreagate]
@parentCode nvarchar(20) -- Code to disaggregate.
, @parentLevel tinyint -- Code's level.
, @withChildren bit -- Disaggragate with childrens?
, @isManual bit -- Is manual or automatic disaggregation?
as
begin
Declare @parentFlag tinyint
, @childrenFlag tinyint
, @trancount int;
[ ... ]
-- Star transaction.
set @trancount = @@trancount;
if @trancount = 0
begin transaction
else
save transaction Disaggreagate;
begin try
-- Update parent code commissioning flag.
Update dbo.CODES
set COMMISIONING_FLAG = @parentFlag
where CODE = @parentCode and CODE_LEVEL = @parentLevel;
-- If it is a disaggregation with children, disaggregate its children.
if (@withChildren = 1)
begin
EXEC dbo.DisaggreagateChildren @parentCode, @parentLevel, @parentFlag, @childrenFlag
end
if @trancount = 0
commit;
end try
begin catch
declare @error int
, @message nvarchar(2048)
, @xactState smallint;
select @error = ERROR_NUMBER()
, @message = ERROR_MESSAGE()
, @xactState = XACT_STATE();
if @xactState = -1
rollback;
if @xactState = 1 and @trancount = 0
rollback
if @xactState = 1 and @trancount > 0
rollback transaction Disaggreagate;
raiserror(N'Error: %i, %s', 16, 1, @error, @message);
end catch
end -- Procedure end.
go
Disaggreagate 中的更新完美运行,但 DissaggreagateWithChildren 中的更新不起作用。执行后我看不到更改。
发生了什么事?
样本数据:
CodeLevel | 3 | 2 | 1 |
----------+---+---+---+
Code | 0 | | |
----------+---+---+---+
Code | | 1 | |
----------+---+---+---+
Code | | | 2 |
----------+---+---+---+
Code | | | 3 |
----------+---+---+---+
Code | | 4 | |
----------+---+---+---+
Code | | | 5 |
----------+---+---+---+
Code | | | 6 |
----------+---+---+---+
在Aggregations 表上,我有代码 0、1 和 4。
在Aggregations_Childs 表上,我有代码 1、2、3、4、5 和 6。
【问题讨论】:
-
很少需要使用循环和/或递归过程调用 - 您通常应该努力编写一个查询,将所有要更新的行及其新值标识为单个
UPDATE查询。不幸的是,这里有太多的机制,我发现很难看出实际应用了什么逻辑。您能否创建一小组样本数据、调用上述代码时使用的参数以及样本数据的预期结果? -
@Damien_The_Unbeliever 我问了,因为我认为我需要在递归过程中添加一个提交。
-
我认为这只是使用
@@rowcount和set rowcount的问题 -
最后,您只是想添加分支,还是从自连接的树中修剪分支?即我有代码 0,其孩子是 1 和 4,其孙子是 2,3(1 岁的孩子)和 5,6(4 岁的孩子)。因此,如果我删除孩子 4,我还需要删除 5,6,因为它们已连接?
标签: sql-server tsql recursion sql-server-2012-express