SQL - 循环 - 复制类别

时间:2009-11-13 19:49:14

标签: sql-server

假设Category表具有categoryId,name和parentCategoryId列,其中categoryId是标识字段。

现在如果我必须复制一个类别并将其分配给新的父级呢?因为它不是一个简单的插入语句。我必须插入所有子类别及其子类别等。我如何跟踪他们的身份字段?我需要在插入时将parentCategoryId分配给它们的子类别。

这个问题清楚了吗?

3 个答案:

答案 0 :(得分:1)

不确定您是在问2个问题还是仅1个问题,即将整个类别复制为新类别(即复制类别)与将现有类别重新分配给新父级 - 每个问题都是不同的问题/解决方案,但让我们从复制整个类别开始。

首先,如果你使用的是基于身份的列,那么你可以在不使用“set identity_insert on”选项的情况下使用 ONLY 方式将光标穿过整个树,从根节点和向下工作(即插入顶级类别,获取新创建的标识值,插入第二级类别等)。如果您处于可以使用“set identity_insert on”的情况,或者您可以使用明确的数字替换身份的使用,那么您可以利用下面的代码。

在此代码中,您会注意到CTE'srecursive CTE'sranking functions的使用,因此这假定为Sql 2005或更高版本。此外,lvl,path和cnt列仅用于演示目的,您可以根据需要查看,而不是在任何最终解决方案中都需要:

declare @root_category_id bigint,
        @start_new_id_value bigint;

-- What category id do we want to move?
select  @root_category_id = 3;
-- Get the current max id and pad a bit...
select  @start_new_id_value = max(categoryId)
from    Category;
select  @start_new_id_value = coalesce(@start_new_id_value,0) + 100;

-- Show our values
select  @root_category_id, @start_new_id_value;

begin tran;
set identity_insert Category on;

-- This query will give you the entire category tree
with subs (catId, parentCatId, catName, lvl, path, new_id, new_parent_id, cnt) as (
    -- Anchor member returns a row for the input manager
    select  catId, parentCatId, catName, 0 as lvl,
            cast(cast(catId as varchar(10)) as varchar(max)) as path,
            @start_new_id_value + row_number() over(order by catId) - 1 as new_id, 
            cast(parentCatId as bigint) as new_parent_id, 
            count(*) over(partition by 0) as cnt
    from    Category
    where   catId = @root_category_id

    union all

    -- recursive member returns next level of children
    select  c.catId, c.parentCatId, c.catName, p.lvl + 1,
            cast(p.path + '.' + cast(catId as varchar(10)) as varchar(max)),
            p.cnt + row_number() over(order by c.catId) + p.new_id - 1 as new_id,
            p.new_id as new_parent_id,
            count(*) over(partition by p.lvl) as cnt
    from    subs as p -- Parent
    join    Category as c -- Child
    on      c.parentCatId = p.catId
)
-- Perform the insert
insert  Category 
        (categoryId, Name, parentCategoryId)
select  s.catId, s.catName, s.parentCatId
from    subs s
--order by path;

set identity_insert Category off;
commit tran;

答案 1 :(得分:0)

有趣的问题。

如果您使用的是SQL 2005+,我认为您可以使用要复制的类别的完整树来构建CTE,这将使其处于临时位置以便远离主表。

然后,您可以使用光标沿树向下工作并更新父级的ID号...

现在我输入它,它似乎不是最有效的解决方案。也许您可以改为使用SELECT语句,更新父ID的ID SELECT

答案 2 :(得分:0)

您是否了解嵌套集?这是在这样的问题中表示数据的另一种方式。我不知道它是否会对此有所帮助,但如果您不了解它,您可能需要考虑它。 http://intelligent-enterprise.informationweek.com/001020/celko.jhtml