Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server SQL-循环-复制类别_Sql Server - Fatal编程技术网

Sql server SQL-循环-复制类别

Sql server SQL-循环-复制类别,sql-server,Sql Server,假设类别表有categoryId、name和parentCategoryId列,其中categoryId是一个标识字段 现在,如果我必须复制一个类别并将其分配给新的父级,该怎么办?因为它不是一个简单的insert语句。我必须插入所有子类别及其子类别等等。我如何跟踪他们的身份字段?插入时,我需要将parentCategoryId分配给它们的子类别 这个问题清楚吗?有趣的问题 如果您使用的是SQL 2005+,我想您可以构建一个CTE,其中包含要复制的类别的完整树,这将把它放在一个临时位置,远离主表

假设类别表有categoryId、name和parentCategoryId列,其中categoryId是一个标识字段

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

这个问题清楚吗?

有趣的问题

如果您使用的是SQL 2005+,我想您可以构建一个CTE,其中包含要复制的类别的完整树,这将把它放在一个临时位置,远离主表

然后,您可以使用光标沿着树向下移动,并更新父项的ID号


现在我输入它,它似乎不是最有效的解决方案。也许您可以改为执行一个奇特的
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——以及它的所有子类别(如果有的话)?天哪,是的,这是正确的。如果一个类别是一个叶子类别,那么它可能也有指向它的产品,但我们可以稍后再担心。这种方法会很好地工作,除非你有非常大的类别要处理——在这种情况下,循环和游标可能会使你的系统缓慢爬行。那么数据集有多大呢?