复制父级和子级属性

时间:2016-10-05 13:09:17

标签: sql sql-server tsql

我在解决克服其他公司的父/子产品类别最合理的方法时遇到了问题。

可以有3个级别的类别。

即。 Mens Clothing(L1)> Shirt(L2)> Short Sleeve(L3)
ShirtShort Sleeve的父级,Mens ClothingShirt的父级。

ParentCategoryId是上面类别的ID。
ParentString是以上所有类别的ID,按级别排列。

(即对于L3产品,它将是L1的Id,然后是L2的Id)  表格设置如下。

CREATE TABLE #Categories
(
CategoryId INT
,CompanyId INT
,ParentCategoryId INT
,CategoryName VARCHAR(255)
,ParentString VARCHAR(20)
)
INSERT INTO #Categories VALUES
(123, 12, NULL, 'Mens Clothing',     NULL),
(124, 12, 123,  'Shirt',            '123-'),
(125, 12, NULL, 'Womens Clothing',  NULL),
(126, 12, 125,  'Shirt',            '125-'),
(127, 12, 124,  'Short Sleeve',     '123-124-'),
(128, 12, NULL, 'Drinks',           NULL),
(129, 12, 128,  'Water',            '128-')

我需要将所有类别和级别复制到CompanyId 13。

3 个答案:

答案 0 :(得分:1)

只是为了好玩,如果你想玩XML和全局搜索和替换。在cteMap2中,您将看到我们对替换字符串非常具体。有时没必要,但比抱歉更安全。需要注意的是,XML部分对字段名称区分大小写。

cteMap1只根据#Categories中的最大值创建标准映射(无论公司如何)

cteMap2再次生成替换字符串,非常具体,没有碰撞的可能性。

然后我们只需在一次通过中应用替换

然后我们将字符串转换为xml,然后将其转换为消费表(Insert Into ...)

Declare @OldCoID int = 12
Declare @NewCoID int = 55

Declare @String varchar(max) = ((Select * from #Categories Where CompanyId=@OldCoID For xml raw))

;with cteMap1 as (
        Select Old  = CategoryID
              ,New  = (Select max(CategoryID) from #Categories) + Row_Number() over (Order By CategoryID)
         From  #Categories
         Where CompanyID = @OldCoID)
    , cteMap2 as (
        Select Old=concat('CategoryId="',Old,'"'),New=concat('CategoryId="',New,'"') From cteMap1
        Union All
        Select Old=concat('ParentCategoryId="',Old,'"'),New=concat('ParentCategoryId="',New,'"') From cteMap1
        Union All
        Select Old=concat('CompanyId="',@OldCoID,'"'),New=concat('CompanyId="',@NewCoID,'"')
        Union All
        Select Old=concat(Old,'-'),New=concat(New,'-') From cteMap1
    )
Select @String = Replace(@String,Old,New) From cteMap2 
Declare @XML xml = @String

Select CategoryId       = xRow.value('@CategoryId[1]','int')
      ,CompanyId        = xRow.value('@CompanyId[1]','int')
      ,ParentCategoryId = xRow.value('@ParentCategoryId[1]','int')
      ,CategoryName     = xRow.value('@CategoryName[1]','varchar(255)')
      ,ParentString     = xRow.value('@ParentString[1]','varchar(20)')
From  @XML.nodes('/row') As A(xRow)

返回

CategoryId  CompanyId   ParentCategoryId    CategoryName    ParentString
130         55          NULL                Mens Clothing   NULL
131         55          130                 Shirt           130-
132         55          NULL                Womens Clothing NULL
133         55          132                 Shirt           132-
134         55          131                 Short Sleeve    130-131-
135         55          NULL                Drinks          NULL
136         55          135                 Water           135-

答案 1 :(得分:0)

首先按最大值移位ID。

declare @shift  int = (select max(CategoryId) from #Categories);
-- data for new company 14 
INSERT  #Categories(
SELECT @shift + CategoryId, 14 companyId, @shift + ParentCategoryId, CategoryName, NULL as ParentString
FROM  #Categories
WHERE companyId = 12;

然后按照原始公司的方式为新公司重新创建ParentString。

答案 2 :(得分:0)

这是一个奇怪的解决方案。

  1. 我们从公司12中输入CTE所有东西,

  2. 我们从此表中找到MAX个ID,然后将其添加到ROW_NUMBER()

  3. ParentString转换为XML,

  4. 选择我们需要的内容,

  5. 得到输出(见下文),可插入Categories表:

    DECLARE @id int 
    
    SELECT @id = MAX(CategoryId) FROM #Categories
    
    ;WITH cte AS (
    SELECT  ROW_NUMBER() OVER (PARTITION BY CompanyId ORDER BY CategoryId) + @id as NewCategoryId,
            CategoryId as OldCategoryId,
            CompanyId,
            ParentCategoryId,
            CategoryName,
            CAST('<p>'+REPLACE(STUFF(ParentString,LEN(ParentString),1,''),'-','</p><p>')+'</p>' as xml) parentxml
    FROM #Categories
    WHERE CompanyId = 12
    )
    
    SELECT  c.NewCategoryId,
            13 as CompanyId,
            c1.NewCategoryId as NewParentCategoryId,
            c.CategoryName,
            (
            SELECT CAST(f.NewCategoryId as nvarchar(max)) +'-'
            FROM cte f
            OUTER APPLY (
                SELECT  t.c.value('.','int') as xpart
                FROM c.parentxml.nodes('/p') as t(c)
            ) x
            WHERE OldCategoryId = x.xpart
            FOR XML PATH('')
            ) as ParentString
    FROM cte c
    LEFT JOIN cte c1 
        ON c1.OldCategoryId = c.ParentCategoryId
    

    输出:

    NewCategoryId   CompanyId   NewParentCategoryId CategoryName    ParentString
    130             13          NULL                Mens Clothing   NULL
    131             13          130                 Shirt           130-
    132             13          NULL                Womens Clothing NULL
    133             13          132                 Shirt           132-
    134             13          131                 Short Sleeve    130-131-
    135             13          NULL                Drinks          NULL
    136             13          135                 Water           135-
    

    修改

    如果CategoryId列是自动递增的IDENTITY列,那么最好使用事务并将IDENTITY_INSERT设置为ON:

    SET IDENTITY_INSERT Categories ON
    BEGIN TRANSACTION
    ...
    COMMIT TRANSACTION
    SET IDENTITY_INSERT Categories OFf