2016-02-18 2 views
0

Учитывая следующий XML все узлы с именем IsEurozone должны быть переименованы в HasFxrEuro.Перемещение узлов в XML и переименовать их с помощью XML DML

<?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> 

ЗАМЕНИТЬ-операция может легко сделать (благодаря Микаэль 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> 
    <CountryIsoAlpha3>USA</CountryIsoAlpha3> 
    <Id>1</Id> 
    <HasFxrEuro>true</HasFxrEuro> 
    </Scenario> 

Но в моем случае мне нужен строгий алфавитный порядок узлов, и поэтому HasFxrEuro должен быть размещен до Id.

Моя идея состояла в том, чтобы сделать что-то вроде

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

и после этого удалить все старые IsEurozone узлы. Но XML DML требует синглтона для вставных операторов. Есть ли другой способ достичь этого с помощью XML DML?

+0

Какую версию SQL Server вы используете? С 2014 года существует «замена значения» XML DML. Я думаю, это может вам помочь. Дополнительная информация: https://msdn.microsoft.com/en-us/library/ms190675.aspx –

+0

Это SQL Server 2012 SP 3. И из того, что я понимаю, «replace value» заменяет значение узла, а не имя. И он не перемещает узел в дереве. – MiGro

ответ

0

Ok, наконец, я получил это работает вручную, идя по документу 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.