Sql server SQL-循环-复制类别
假设类别表有categoryId、name和parentCategoryId列,其中categoryId是一个标识字段 现在,如果我必须复制一个类别并将其分配给新的父级,该怎么办?因为它不是一个简单的insert语句。我必须插入所有子类别及其子类别等等。我如何跟踪他们的身份字段?插入时,我需要将parentCategoryId分配给它们的子类别 这个问题清楚吗?有趣的问题 如果您使用的是SQL 2005+,我想您可以构建一个CTE,其中包含要复制的类别的完整树,这将把它放在一个临时位置,远离主表 然后,您可以使用光标沿着树向下移动,并更新父项的ID号Sql server SQL-循环-复制类别,sql-server,Sql Server,假设类别表有categoryId、name和parentCategoryId列,其中categoryId是一个标识字段 现在,如果我必须复制一个类别并将其分配给新的父级,该怎么办?因为它不是一个简单的insert语句。我必须插入所有子类别及其子类别等等。我如何跟踪他们的身份字段?插入时,我需要将parentCategoryId分配给它们的子类别 这个问题清楚吗?有趣的问题 如果您使用的是SQL 2005+,我想您可以构建一个CTE,其中包含要复制的类别的完整树,这将把它放在一个临时位置,远离主表
现在我输入它,它似乎不是最有效的解决方案。也许您可以改为执行一个奇特的
SELECT
语句,它会在父ID的SELECT
ing时更新它的ID?您知道嵌套集吗?这是在这样的问题中表示数据的另一种方法。我不知道这会不会有帮助,但是如果你不知道它,你可能会想它。 不确定是问2个问题还是只问1个问题,即复制整个类别作为新类别(即复制类别)还是将现有类别重新分配给新的父类别-每个问题/解决方案都不同,但让我们从复制整个类别开始
首先,如果您使用的是基于标识的列,那么在不使用“set identity_insert on”选项的情况下,唯一可以做到的方法是从根节点开始向下移动光标,遍历整个树(即插入顶级类别、获取新创建的标识值、插入第二级类别等)。如果您处于可以使用“set identity_insert on”的场景中,或者如果您可以使用显式数字替换标识的使用,那么您可以利用下面的代码
在这段代码中,您会注意到和的使用,因此假设使用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;
我想这对以前做过这种工作的人来说已经足够清楚了。对于这类问题,我有一个混乱的解决方案(使用CTEs)可以用于分层数据。如果没有人发布更好的东西——我希望他们会这样做——我会描述一下我做这件事的丑陋方式。你想复制一个类别——它可以是顶级或中级parend——以及它的所有子类别(如果有的话)?天哪,是的,这是正确的。如果一个类别是一个叶子类别,那么它可能也有指向它的产品,但我们可以稍后再担心。这种方法会很好地工作,除非你有非常大的类别要处理——在这种情况下,循环和游标可能会使你的系统缓慢爬行。那么数据集有多大呢?