移动XML中的节点并使用XML DML重命名它们

时间:2016-02-18 14:37:44

标签: sql-server tsql xml-dml

鉴于以下XML,所有名为 IsEurozone 的节点都必须重命名为 HasFxrEuro

<?xml version="1.0" encoding="utf-8"?>
<MacroScenarios>
  <MacroScenario>
    <Id>1</Id>
    <Name>Macro Scenario 1</Name>
    <Scenarios>
      <Scenario>
        <CountryIsoAlpha3>USA</CountryIsoAlpha3>
        <Id>1</Id>
        <IsEurozone>true</IsEurozone>
      </Scenario>
      <Scenario>
        <CountryIsoAlpha3>GER</CountryIsoAlpha3>
        <Id>2</Id>
        <IsEurozone>true</IsEurozone>
      </Scenario>
    </Scenarios>
  </MacroScenario>
</MacroScenarios>

替换操作很容易完成(感谢Mikael Erikssons发布How to rename XML node name in a SQL Server):

UPDATE [dbo].[MacroScenarioSets] set
[ContentAsXml] = 
        replace(
            replace(
                cast(ContentAsXml as nvarchar(max)), 
                '<IsEurozone>', 
                '<HasFxrEuro>'),
            '</IsEurozone>', 
            '</HasFxrEuro>')

之后,Scenario节点的内容如下所示:

  <Scenario>
    <CountryIsoAlpha3>USA</CountryIsoAlpha3>
    <Id>1</Id>
    <HasFxrEuro>true</HasFxrEuro>
  </Scenario>

但在我的情况下,我需要严格按字母顺序排列节点,因此必须在 Id 之前放置 HasFxrEuro

我的想法是做一些像

这样的事情
UPDATE [dbo].[MacroScenarioSets]
SET ContentAsXml.modify('insert 
<HasFxrEuro>{(/MacroScenarios/MacroScenario/Scenarios/Scenario/IsEurozone/text())}</HasFxrEuro>
after (/MacroScenarios/MacroScenario/Scenarios/Scenario/CountryIsoAlpha3)')

之后删除所有旧的 IsEurozone 节点。但XML DML需要inserton语句的单例。有没有其他方法可以通过XML DML实现这一目标?

1 个答案:

答案 0 :(得分:0)

好的,最后我通过手动浏览XML文档来运行它:

    declare @scenarioCursor int = 1
    declare @macroScenarioCursor int = 1

    while 1 = 1
    begin

            -- Add HasFxrEuro with the value of IsEurozone
           UPDATE @myxml
           SET content.modify('
               insert 
                <HasFxrEuro>{(/MacroScenarios/MacroScenario[sql:variable("@macroScenarioCursor")]/Scenarios/Scenario[sql:variable("@scenarioCursor")]/IsEurozone[1]/text())}</HasFxrEuro>
               after ((/MacroScenarios/MacroScenario[sql:variable("@macroScenarioCursor")]/Scenarios/Scenario[sql:variable("@scenarioCursor")]/CountryIsoAlpha3))[1]')
           WHERE content.exist('
                (/MacroScenarioSet/MacroScenarios/MacroScenario[sql:variable("@macroScenarioCursor")]/Scenarios/Scenario[sql:variable("@scenarioCursor")])') = 1

           if @@ROWCOUNT = 0 
           begin
                -- the end
                if @scenarioCursor = 1
                    break;
                else
                    -- increment cursor over MacroScenario, reset cursor over Scenario
                   begin
                         SET @macroScenarioCursor = @macroScenarioCursor + 1
                         SET @scenarioCursor = 1
                   end 
            end       
            else
                begin

                    -- HasFxrEuro has been added remove IsEurozone
                    UPDATE @myxml
                    SET content.modify('
                        delete (/MacroScenarios/MacroScenario[sql:variable("@macroScenarioCursor")]/Scenarios/Scenario[sql:variable("@scenarioCursor")]/IsEurozone)')

                    -- increment Scenario cursor
                    SET @scenarioCursor = @scenarioCursor + 1
               end

end

解决方案非常缓慢。但我不知道如何在SQL中解决这个问题。