假设Category表具有categoryId,name和parentCategoryId列,其中categoryId是标识字段。
现在如果我必须复制一个类别并将其分配给新的父级呢?因为它不是一个简单的插入语句。我必须插入所有子类别及其子类别等。我如何跟踪他们的身份字段?我需要在插入时将parentCategoryId分配给它们的子类别。
这个问题清楚了吗?
答案 0 :(得分:1)
不确定您是在问2个问题还是仅1个问题,即将整个类别复制为新类别(即复制类别)与将现有类别重新分配给新父级 - 每个问题都是不同的问题/解决方案,但让我们从复制整个类别开始。
首先,如果你使用的是基于身份的列,那么你可以在不使用“set identity_insert on”选项的情况下使用 ONLY 方式将光标穿过整个树,从根节点和向下工作(即插入顶级类别,获取新创建的标识值,插入第二级类别等)。如果您处于可以使用“set identity_insert on”的情况,或者您可以使用明确的数字替换身份的使用,那么您可以利用下面的代码。
在此代码中,您会注意到CTE's,recursive CTE's和ranking 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