2016-09-08 5 views
2

Ich habe ein XML wie unten:Verwendung Variable in XPath für SQL Server

<BODY> 
    <RECORD> 
     <PA0002_NATIO>CH</PA0002_NATIO> 
     <PA0001_CITY>Lugano</PA0001_CITY> 
     <PA0005_VALUE>1000</PA0005_VALUE> 
    </RECORD> 
    <RECORD> 
     <PA0002_NATIO>DE</PA0002_NATIO> 
     <PA0001_CITY>Berlin</PA0001_CITY> 
     <PA0005_VALUE>2000</PA0005_VALUE> 
    </RECORD> 
    <RECORD> 
     <PA0002_NATIO>IT</PA0002_NATIO> 
     <PA0001_CITY>Roma</PA0001_CITY> 
     <PA0005_VALUE>3000</PA0005_VALUE> 
    </RECORD> 
</BODY> 

Ich mag den Wert für den Tag <PA0002_NATIO> in allen <RECORD> Knoten und ändern, um zu tun, dass ich die Anzahl der Zählung die <RECORD> Knoten und ich mache eine Schleife wie folgt, der neue Wert wird aus einer Tabelle entnommen.

if @countNodes > 0 
    begin 
    set @indexCount = 1 
    while @indexCount <= @countNodes 
     begin   

      -- get the value from the node   
      set @nodevalue = (@xml.value('(//RECORD[sql:variable("@indexCount")]/PA0002_NATIO/text())[1]', 'nvarchar(50)')) 

      -- find in the table the value to be replaced 
      set @repvalue = (select [Target Code] from [Ronal].[dbo].['Value Mapping$'] 
      where [List Name]='Nationality' and [SAP Code][email protected]) 

      -- replace the value in the node 
      set @xml.modify(' 
      replace value of 
       (//RECORD[sql:variable("@indexCount")]/PA0002_NATIO/text())[1] 
      with 
       sql:variable("@repvalue") 
      '); 


      SET @Indexcount= @Indexcount + 1; 
     end 
end 

END

jetzt ist die Idee, ein Generikum ersetzen mit einer Variablen in XPath statt mit

set @nodevalue = (@xml.value('(//RECORD[sql:variable("@indexCount")]/PA0002_NATIO/text())[1]', 'nvarchar(50)')) 

I

set @nodevalue = (@xml.value('(//RECORD[sql:variable("@indexCount")]/[sql:variable("@tag")]/text())[1]', 'nvarchar(50)')) 

und verwenden würden zu machen Natürlich würde ich die gleiche Syntax verwenden, um

zu ersetzen
-- replace the value in the node 
set @xml.modify(' 
replace value of 
    (//RECORD[sql:variable("@indexCount")]/[sql:variable("@tag")]/text())[1] 
with 
    sql:variable("@repvalue") 
'); 

Wo der @tag Variable enthält <PA0002_NATIO> sondern auch <PA0001_CITY> und so weiter, die Daten von einem anderen Tisch zu bekommen, die den Tag-Namen speichern.

Wie kann ich das tun?

+0

Statt 'sql: variable' Sie Tabelle, die Sie verwenden, müssen beitreten können' sql: column' – gofr1

+0

i don habe keine Tabelle, ich habe nur ein xml – zanza67

+0

Können Sie zeigen, welche Ausgabe Sie von oben XML erhalten müssen? Warum Sie sagen, dass Sie keine Tabelle haben, wenn Sie diese verwenden, um Wert für die Aktualisierung zu erhalten: 'wählen Sie [Zielcode] aus [Ronal]. [Dbo]. ['Wertezuordnung $'] wobei [Name der Liste] = 'Nationalität 'und [SAP-Code] = @ nodevalue' – gofr1

Antwort

1

Sie benötigen eine heikle .modify mit Schleife:

--declare table with names and ids like you posted in comment 
DECLARE @test TABLE (
    Name nvarchar(2), 
    id nvarchar(2) 
) 

INSERT INTO @test VALUES 
('CH', '00'), 
('DE', '01'), 
('IT', '02') 


DECLARE @xml XML = ' 
    <BODY> 
      <RECORD> 
       <PA0002_NATIO>CH</PA0002_NATIO> 
       <PA0001_CITY>Lugano</PA0001_CITY> 
       <PA0005_VALUE>1000</PA0005_VALUE> 
      </RECORD> 
      <RECORD> 
       <PA0002_NATIO>DE</PA0002_NATIO> 
       <PA0001_CITY>Berlin</PA0001_CITY> 
       <PA0005_VALUE>2000</PA0005_VALUE> 
      </RECORD> 
      <RECORD> 
       <PA0002_NATIO>IT</PA0002_NATIO> 
       <PA0001_CITY>Roma</PA0001_CITY> 
       <PA0005_VALUE>3000</PA0005_VALUE> 
      </RECORD> 
    </BODY>'; 

DECLARE @Counter int = 1, 
     @newValue nvarchar(max), 
     @nodename nvarchar(max) ='PA0002_NATIO' 

WHILE @Counter <= @xml.value('fn:count(//*//*//*[local-name()=sql:variable("@nodename")])','int') 
BEGIN 
    SELECT @newValue = id 
    FROM @test 
    WHERE Name = CAST(@xml.query('((/*/*/*[local-name()=sql:variable("@nodename")])[position()=sql:variable("@Counter")]/text())[1]') as nvarchar(2)) 

    SET @xml.modify('replace value of ((/*/*/*[local-name()=sql:variable("@nodename")])[position()=sql:variable("@Counter")]/text())[1] with sql:variable("@newValue")') 

    SET @Counter = @Counter + 1; 
END 

SELECT @xml; 

Ausgang:

<BODY> 
    <RECORD> 
    <PA0002_NATIO>00</PA0002_NATIO> 
    <PA0001_CITY>Lugano</PA0001_CITY> 
    <PA0005_VALUE>1000</PA0005_VALUE> 
    </RECORD> 
    <RECORD> 
    <PA0002_NATIO>01</PA0002_NATIO> 
    <PA0001_CITY>Berlin</PA0001_CITY> 
    <PA0005_VALUE>2000</PA0005_VALUE> 
    </RECORD> 
    <RECORD> 
    <PA0002_NATIO>02</PA0002_NATIO> 
    <PA0001_CITY>Roma</PA0001_CITY> 
    <PA0005_VALUE>3000</PA0005_VALUE> 
    </RECORD> 
</BODY> 
+0

bekomme, danke so viel gofr1, aber in deinem Fall hast du PA0002_NATIO fest programmiert, was ich vermeiden will. Was ich erreichen möchte, ist eine Parameterversion von replace, wobei der Wert, der für das Tag ersetzt werden soll, von dem dynamischen XPath abhängt, den ich erstellen möchte. Zum Beispiel möchte ich den Wert für Record \ PA0002_NATIO ersetzen, aber auch für Record \ PA0001_CITY, also um todo, dass ich zweimal schreiben muss, meine Idee ist, die PA0002_NATIO und PA0001_CITY irgendwohin (Tabelle zum Beispiel) und zur Laufzeit als Variable zu liefern der xpath, um den Wert zu ersetzen. vielleicht habe ich das nicht richtig erklärt, tut mir leid, – zanza67

+0

Überprüfen Sie meine Änderungen. '@nodename nvarchar (max) = 'PA0002_NATIO'' in' @ nodename' übergeben Sie den Knotennamen, den Sie benötigen. – gofr1

+0

danke ich werde einen Blick – zanza67