MSSQL批量字符串到XML插入

时间:2017-05-19 14:43:01

标签: sql-server xml tsql

目前我们导入一个表Import_File,它有一个Options列,该列具有分隔值。 我们需要将这些分隔值加载到不同的表中。

目前我们一次只做一行,因为行数可以是100k +

有没有办法加快下面的代码?

Declare @InvId uniqueidentifier
Declare @xml xml
Declare CurrFeatureList Cursor For
Select 
    import.InventoryId,
     N'<root><r><![CDATA[' + replace( import.OPTIONS ,',',']]></r><r><![CDATA[') + ']]></r></root>'
From                Import_File import with (nolock)
Where
    import.options IS NOT NULL
    And ISNULL(import.IsFeatureProcessed,0) = 0
    And LEN(ISNULL(import.OPTIONS,''))>10
    And import.InventoryId Is Not Null

OPEN CurrFeatureList

FETCH NEXT FROM CurrFeatureList
INTO @InvId, @xml

Print 'Inventory Import #10000'
Print GetDate()
WHILE @@FETCH_STATUS = 0
BEGIN
    BEGIN TRY

        Insert Into Import_File_Feature
        (
            FeatureId,
            InventoryId,
            FeatureText,
            FeatureGroup,
            FeatureCategory,
            FeatureIsAvailable,
            FeatureIsStandard
        )
        Select 
            NEWID(),
            @InvId,
            t.value('.','varchar(250)'),
            '',
            '',
            1,
            1
        From @xml.nodes('//root/r') as a(t)

        FETCH NEXT FROM CurrFeatureList
        INTO @InvId, @xml
    END TRY
    BEGIN CATCH
        Print 'Error    ' 
        Print @InvId 
        Print   ERROR_NUMBER() 
        Print   ERROR_SEVERITY()
        Print   ERROR_STATE()
        Print   ERROR_PROCEDURE()
        Print   ERROR_LINE()
        Print   ERROR_MESSAGE()

        FETCH NEXT FROM CurrFeatureList
        INTO @InvId, @xml
    END CATCH
END

Close CurrFeatureList
Deallocate CurrFeatureList
GO

1 个答案:

答案 0 :(得分:2)

我见过光标的唯一原因&amp;用于此类事情的TRY / CATCH块用于在开发新的ETL过程时识别和分析不良记录。如果那不是你正在做的事情那么光标不是必需的,会让你慢下来。

让我们回顾一下你在做什么:

  1. 您将数据拖入游标(CurrFeatureList)并将Import_File.Options转换为XML字段,以便稍后使用XML NODES方法“拆分”您的字符串。
  2. 开出光标
  3. 对于每个InventoryId,您: 一个。将Import_File.Options拆分为多行 湾将InventoryId和关联的行插入Import_File_Feature C。如果出现错误则将其打印出来并转到下一条记录
  4. 你应该做什么

    请注意我是如何使用XML节点拆分此字符串的:

    DECLARE @x varchar(100) = 'abc,cde,fff';
    
    SELECT item = xxx.value('(text())[1]', 'varchar(100)')
    FROM (VALUES (CAST(('<r>'+REPLACE(@x,',','</r><r>') +'</r>') AS xml))) x(xx)
    CROSS APPLY xx.nodes('r') xxx(xxx);
    

    <强>结果

    item
    -----
    abc
    cde
    fff
    

    选项1

    将初始连接和后续XML / XML节点拆分器逻辑组合到一个语句中并执行插入:

    WITH 
    yourData AS
    (
      Select 
          import.InventoryId,
           x = N'<r><![CDATA[' + replace( import.OPTIONS ,',',']]></r><r><![CDATA[') + ']]></r>'
      From Import_File import with (nolock)
      Where
      import.options IS NOT NULL
      And ISNULL(import.IsFeatureProcessed,0) = 0
      And LEN(ISNULL(import.OPTIONS,''))>10
      And import.InventoryId Is Not Null
    ),
    split AS
    (
      SELECT InventoryId, item = i.value('.', 'varchar(8000)')
      FROM yourData
      CROSS APPLY x.nodes('r') s(i)  
    )
    Insert Into Import_File_Feature
    (
      FeatureId,
      InventoryId,
      FeatureText,
      FeatureGroup,
      FeatureCategory,
      FeatureIsAvailable,
      FeatureIsStandard
     )
    Select 
       newid(),
       import.InventoryId,
       item, -- this is the split out item from import.Options
        '',
        '',
        1,
        1
    FROM split;
    

    选项2

    获取DelimitedSplit8K的副本并使用它来进行拆分。

    WITH split AS
    (
      Select 
          import.InventoryId,
          import.OPTIONS
      From Import_File import with (nolock)
      CROSS APPLY dbo.DelimitedSplit8K(import.OPTIONS, ',')
      Where
      import.options IS NOT NULL
      And ISNULL(import.IsFeatureProcessed,0) = 0
      And LEN(ISNULL(import.OPTIONS,''))>10
      And import.InventoryId Is Not Null
    )
    Insert Into Import_File_Feature
    (
      FeatureId,
      InventoryId,
      FeatureText,
      FeatureGroup,
      FeatureCategory,
      FeatureIsAvailable,
      FeatureIsStandard
     )
    Select 
       newid(),
       import.InventoryId,
       item,
        '',
        '',
        1,
        1
    FROM split
    

    请注意,因为我没有任何表定义或示例数据,所以我无法测试上面的代码。