【问题标题】:Copying Parent and child attributes复制父子属性
【发布时间】:2016-10-06 12:57:04
【问题描述】:

我在找出最合乎逻辑的方式为另一家公司克隆父/子产品类别时遇到了问题。

可以有 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。

【问题讨论】:

  • 您可能会在this 答案中找到一些有价值的东西。

标签: sql sql-server tsql


【解决方案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-

【讨论】:

  • 不错的一个!也想过这种方法,但最后只为ParentString 使用了XML。 +1。
  • @gofr1 谢谢。有些人认为 XML/String 操作是邪恶的。我,没那么多。
【解决方案2】:

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

  1. 我们把 12 号公司的所有东西都放进了 CTE,

  2. 我们从这个表中找到MAX id,然后添加到ROW_NUMBER()

  3. ParentString转换为XML,

  4. 选择我们需要的,

得到了可以插入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

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

【讨论】:

  • 乍一看/测试,这看起来会起作用!当我真正开始运行更新时会更新。感谢您的帮助!
  • 添加一些交易和身份插入的东西。
【解决方案3】:

按最大值排列的第一个班次 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。

【讨论】:

    猜你喜欢
    • 2015-07-26
    • 2020-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多