Columns with a name
Applies to: SQL Server Azure SQL Database Azure SQL Managed Instance
The following are the specific conditions in which rowset columns with a name are mapped, case-sensitive, to the resulting XML:
The column name starts with an at sign (
@
).The column name doesn't start with an at sign (
@
).The column name doesn't start with an at sign (
@
) and contains a slash mark (/
).Several columns share the same prefix.
One column has a different name.
Column name starts with an at sign (@
)
If the column name starts with an at sign (@
) and doesn't contain a slash mark (/
), an attribute of the row
element that has the corresponding column value is created. For example, the following query returns a two-column (@PmId, Name
) rowset. In the resulting XML, a PmId
attribute is added to the corresponding row
element and a value of ProductModelID
is assigned to it.
SELECT ProductModelID as "@PmId",
Name
FROM Production.ProductModel
WHERE ProductModelID = 7
FOR XML PATH;
This is the result:
<row PmId="7">
<Name>HL Touring Frame</Name>
</row>
Attributes must come before any other node types, such as element nodes and text nodes, in the same level. The following query will return an error:
SELECT Name,
ProductModelID as "@PmId"
FROM Production.ProductModel
WHERE ProductModelID = 7
FOR XML PATH;
Column name doesn't start with an at sign (@
)
If the column name doesn't start with an at sign (@
), isn't one of the XPath node tests, and doesn't contain a slash mark (/
), an XML element that is a subelement of the row element, row
by default, is created.
The following query specifies the column name, the result. Therefore, a result
element child is added to the row
element.
SELECT 2 + 2 as result
for xml PATH;
This is the result:
<row>
<result>4</result>
</row>
The following query specifies the column name, ManuWorkCenterInformation
, for the XML returned by the XQuery specified against Instructions
column of xml type. Therefore, a ManuWorkCenterInformation
element is added as a child of the row
element.
SELECT
ProductModelID,
Name,
Instructions.query(
'declare namespace MI="http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/ProductModelManuInstructions";
/MI:root/MI:Location
') as ManuWorkCenterInformation
FROM Production.ProductModel
WHERE ProductModelID=7
FOR XML PATH;
This is the result:
<row>
<ProductModelID>7</ProductModelID>
<Name>HL Touring Frame</Name>
<ManuWorkCenterInformation>
<MI:Location ...LocationID="10" ...></MI:Location>
<MI:Location ...LocationID="20" ...></MI:Location>
...
</ManuWorkCenterInformation>
</row>
Column name doesn't start with an at sign (@
) and contains a slash mark (/
)
If the column name doesn't start with an at sign (@
), but contains a slash mark (/
), the column name indicates an XML hierarchy. For example, if the column name is "Name1/Name2/Name3.../Namen", each Namei represents an element name that is nested in the current row element (for i = 1) or that is under the element that has the name Namei-1. If Namen starts with @
, it's mapped to an attribute of Namen-1 element.
For example, the following query returns an employee ID and name that are represented as a complex element EmpName
that contains a First
, Middle
, and Last
name.
SELECT EmployeeID "@EmpID",
FirstName "EmpName/First",
MiddleName "EmpName/Middle",
LastName "EmpName/Last"
FROM HumanResources.Employee E, Person.Contact C
WHERE E.EmployeeID = C.ContactID AND
E.EmployeeID = 1
FOR XML PATH;
The column names are used as a path in constructing XML in the PATH mode. The column name that contains employee ID values, starts with '@'. Therefore, an attribute, EmpID
, is added to the row
element. All other columns include a slash mark (/
) in the column name that indicates hierarchy. The resulting XML will have the EmpName
child under the row
element, and the EmpName
child will have First
, Middle
and Last
element children.
<row EmpID="1">
<EmpName>
<First>Gustavo</First>
<Last>Achong</Last>
</EmpName>
</row>
The employee middle name is null and, by default, the null value maps to the absence of the element or attribute. If you want elements generated for the NULL values, you can specify the ELEMENTS directive with XSINIL as shown in this query.
SELECT EmployeeID "@EmpID",
FirstName "EmpName/First",
MiddleName "EmpName/Middle",
LastName "EmpName/Last"
FROM HumanResources.Employee E, Person.Contact C
WHERE E.EmployeeID = C.ContactID AND
E.EmployeeID = 1
FOR XML PATH, ELEMENTS XSINIL;
This is the result:
<row xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
EmpID="1">
<EmpName>
<First>Gustavo</First>
<Middle xsi:nil="true" />
<Last>Achong</Last>
</EmpName>
</row>
By default, the PATH mode generates element-centric XML. Therefore, specifying the ELEMENTS directive in a PATH mode query has no effect. However, as shown in the previous example, the ELEMENTS directive is useful with XSINIL to generate elements for null values.
Besides the ID and name, the following query retrieves an employee address. As per the path in the column names for address columns, an Address
element child is added to the row
element and the address details are added as element children of the Address
element.
SELECT EmployeeID "@EmpID",
FirstName "EmpName/First",
MiddleName "EmpName/Middle",
LastName "EmpName/Last",
AddressLine1 "Address/AddrLine1",
AddressLine2 "Address/AddrLIne2",
City "Address/City"
FROM HumanResources.Employee E,
Person.Contact C,
Person.Address A
WHERE E.EmployeeID = C.ContactID
AND E.AddressID = A.AddressID
AND E.EmployeeID = 1
FOR XML PATH;
This is the result:
<row EmpID="1">
<EmpName>
<First>Gustavo</First>
<Last>Achong</Last>
</EmpName>
<Address>
<AddrLine1>7726 Driftwood Drive</AddrLine1>
<City>Monroe</City>
</Address>
</row>
Several columns share the same path prefix
If several subsequent columns share the same path prefix, they're grouped together under the same name. If different namespace prefixes are being used even if they're bound to the same namespace, a path is considered different. In the previous query, the FirstName
, MiddleName
, and LastName
columns share the same EmpName
prefix. Therefore, they're added as children of the EmpName
element. This is also the case when you were creating the Address
element in the previous example.
One column has a different name
If a column with a different name appears in between, it will break the grouping, as shown in the following modified query. The query breaks the grouping of FirstName
, MiddleName
, and LastName
, as specified in the previous query, by adding address columns in between the FirstName
and MiddleName
columns.
SELECT EmployeeID "@EmpID",
FirstName "EmpName/First",
AddressLine1 "Address/AddrLine1",
AddressLine2 "Address/AddrLIne2",
City "Address/City",
MiddleName "EmpName/Middle",
LastName "EmpName/Last"
FROM HumanResources.EmployeeAddress E,
Person.Contact C,
Person.Address A
WHERE E.EmployeeID = C.ContactID
AND E.AddressID = A.AddressID
AND E.EmployeeID = 1
FOR XML PATH;
As a result, the query creates two EmpName
elements. The first EmpName
element has the FirstName
element child and the second EmpName
element has the MiddleName
and LastName
element children.
This is the result:
<row EmpID="1">
<EmpName>
<First>Gustavo</First>
</EmpName>
<Address>
<AddrLine1>7726 Driftwood Drive</AddrLine1>
<City>Monroe</City>
</Address>
<EmpName>
<Last>Achong</Last>
</EmpName>
</row>