Search code examples
sqlsql-serverxmlsql-server-2008sqlxml

Split FOR XML PATH results into separate rows


I have the following query:

SELECT
    101 AS TeacherID
    ,s.ID
    ,s.First
    ,s.Last
FROM dbo.Students s
FOR XML PATH('Student'), ROOT('Students')

which generates output:

<Students>
  <Student>
    <TeacherID>101</TeacherID>
    <ID>14</ID>
    <First>Mark</First>
    <Last>Smith</Last>
  </Student>
  <Student>
    <TeacherID>101</TeacherID>
    <ID>15</ID>
    <First>Josephina</First>
    <Last>Hewitt</Last>
  </Student>
</Students>

I want to break each group into its own rows (into a single XMLFormat column):

AdministratorID   AdministratorName   XMLFormat
------------------------------------------------------------------------------------------------------------------------------------
125               Bertha              <Student><TeacherID>101</TeacherID><ID>14</ID><First>Mark</First><Last>Smith</Last></Student>
125               Bertha              <Student><TeacherID>101</TeacherID><ID>15</ID><First>Josephina</First><Last>Hewitt</Last></Student>

I tried using the Table and Column Alias method:

SELECT  125 AS AdministratorID,
        'Bertha' AS AdministratorName,
        t.c AS XMLFormat
FROM 
(   
    SELECT
        101 AS TeacherID
        ,s.ID
        ,s.First
        ,s.Last
    FROM dbo.Students s
    FOR XML PATH('Student'), ROOT('Students')
) t(c)

but this query generates a single row of data, with the entire XML in the single XMLFormat field.

I thought I may need to use the .nodes() method, but when I add .nodes('/Students/Student') to the t(c) alias, I get 'Incorrect syntax near '.'.

I want to avoid putting the data into an XML variable before using the .nodes() method, because the text could be very long.


Solution

  • select
        125 as AdministratorID,
        'Bertha' as AdministratorName,
        (
            select
                101 as TeacherID, s.ID, s.First, s.Last
            for xml path('Student'), type
        ) as XMLFormat
    from dbo.Students s