sql-serverxqueryxquery-sqlflwor

Using FLWOR to get data from another table


I have a table in SQL Server 2012 with this structure:

CREATE TABLE [dbo].[tblStepList]
(
    [ToDoId] [int] IDENTITY(1,1) NOT NULL,
    [Data] [xml] NOT NULL
)

And the Data column is of type XML and contents like this:

<Steplist>
  <Step>
    <StepId>e36a3450-1c8f-44da-b4d0-58e5bfe2a987</StepId>
    <Rank>1</Rank>
    <IsComplete>false</IsComplete>
    <TextReadingName>bug-8588_Updated3</TextReadingName>     
  </Step>
  <Step>
    <StepId>4078c1b1-71ea-4578-ba61-d2f6a5126ba1</StepId>
    <Rank>2</Rank>
    <TextReadingName>reading1</TextReadingName>
  </Step>
</Steplist>'

I want to update each row of the table with my new xml to look with new node named TextReadingId after TextReading name

I have a secondary table with text reading values stepid and textreadingid

StepId                                TextReadingId 
---------------------------------------------------
e36a3450-1c8f-44da-b4d0-58e5bfe2a987    118
4078c1b1-71ea-4578-ba61-d2f6a5126ba1    119
d466a8ee-9214-4b9c-94f9-2117f5dffe93    401

And I want my TextReadingId values to come from the table above

 <Steplist>
          <Step>
            <StepId>e36a3450-1c8f-44da-b4d0-58e5bfe2a987</StepId>
            <Rank>1</Rank>
            <IsComplete>false</IsComplete>
            <TextReadingName>bug-8588_Updated3</TextReadingName>    
          <TextReadingId>118</TextReadingId>   
          </Step>
          <Step>
            <StepId>4078c1b1-71ea-4578-ba61-d2f6a5126ba1</StepId>
            <Rank>2</Rank>
            <TextReadingName>reading1</TextReadingName>
          <TextReadingId>401</TextReadingId> 
          </Step>
        </Steplist>';

This is what I tried but it is not working as expected

DECLARE @i int;

SELECT
    @i = s.data.value('count(/Steplist/Step)', 'nvarchar(max)')
FROM 
    tblStepList s

SET data.modify('insert <TextReadingId>{sql:variable("@i")}</TextReadingId> as last into (/Steplist/Step[sql:variable("@i")])[1]')

PRINT @i

Here is another answer that helped but it does not join with my other table for the results


Solution

  • The easiest way to do this is to rebuild each Step node and then aggregate it back up using FOR XML

    Within the correlated subquery, we do the following:

    UPDATE sl
    SET Data = (
        SELECT v.Step.query('
    <Step>{./*,
            if (not(./TextReadingId)) then
                <TextReadingId>{sql:column("sr.TextReadingId")}</TextReadingId>
            else ()
            }
    </Step>
        ')
        FROM sl.Data.nodes('/Steplist/Step') v(Step)
        LEFT JOIN StepReading sr ON sr.StepId = v.Step.value('(StepId/text())[1]','uniqueidentifier')
        FOR XML PATH(''), ROOT('Steplist'), TYPE
    )
    FROM tblStepList sl;
    

    SQL Fiddle