Не уверен, если вы задаете 2 вопроса или только 1, то есть репликацию всей категории как новой категории (т.е. копирование категории) или повторное присвоение существующей категории новому родителю - у каждого будут разные проблемы / решения, но давайте начнем с копирования всей категории.
Во-первых, если вы используете столбец на основе идентификаторов, способ ONLY , который вы можете сделать без использования опции «set identity_insert on», будет заключаться в перемещении по всему дереву, начиная с корневые узлы и работа вниз (т.е. вставьте категорию (ии) верхнего уровня, получите вновь созданные значения идентичности, вставьте категории второго уровня и т. д.). Если вы находитесь в сценарии, в котором вы можете использовать «set identity_insert on», или если вы можете заменить использование тождеств с явными числами, то вы можете использовать приведенный ниже код.
В этом коде вы заметите использование *1008*, рекурсивных CTE и функций ранжирования , поэтому это предполагает 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;