问题
I'm using FOR XML PATH
to construct XML out of a table in SQL Server 2008R2. The XML has to be constructed as follows:
<Root>
<OuterElement>
<NumberNode>1</NumberNode>
<FormattedNumberNode>0001</KFormattedNumberNode>
<InnerContainerElement>
<InnerNodeOne>0240</InnerNodeOne>
<InnerNodeStartDate>201201</InnerNodeStartDate>
</InnerContainerElement>
</OuterElement>
</Root>
According to the schema files, the InnerContainerElement
is optional, while the InnerNodeOne
is required. The schema files aren't set up by me, are quite complex, referring each other and not having explicit XSD-namespaces, so I can't easily load them into the database.
The XML has to be created from a table, which is filled using the following query:
SELECT
1 AS NumberNode
, '0001' AS [FormattedNumberNode]
, '0240' AS [InnerNodeOne]
, '201201' AS [InnerNodeStartDate]
INTO #temporaryXMLStore
UNION
SELECT
2 AS NumberNode
, '0001' AS [FormattedNumberNode]
, NULL AS [InnerNodeOne]
, NULL AS [InnerNodeStartDate]
I can think of two ways to construct this XML with FOR XML PATH
.
1) Using 'InnerContainerElement' as named result from an XML subquery:
SELECT
NumberNode
, [FormattedNumberNode]
, (
SELECT
[InnerNodeOne]
, [InnerNodeStartDate]
FOR XML PATH(''), TYPE
) AS [InnerContainerElement]
FROM #temporaryXMLStore
FOR XML PATH('OuterElement'), ROOT('Root') TYPE
2) Using 'InnerContainerElement' as an output element from an XML subquery, but without naming it:
SELECT
NumberNode
, [FormattedNumberNode]
, (
SELECT
[InnerNodeOne]
, [InnerNodeStartDate]
FOR XML PATH('InnerContainerElement'), TYPE
)
FROM #temporaryXMLStore
FOR XML PATH('OuterElement'), ROOT('Root'), TYPE
However, none of them gives the desired result: in both cases, the result looks like
<Root>
<OuterElement>
<NumberNode>1</NumberNode>
<FormattedNumberNode>0001</FormattedNumberNode>
<InnerContainerElement>
<InnerNodeOne>0240</InnerNodeOne>
<InnerNodeStartDate>201201</InnerNodeStartDate>
</InnerContainerElement>
</OuterElement>
<OuterElement>
<NumberNode>2</NumberNode>
<FormattedNumberNode>0001</FormattedNumberNode>
<InnerContainerElement></InnerContainerElement>
<!-- Or, when using the second codeblock: <InnerContainerElement /> -->
</OuterElement>
</Root>
Whenever InnerContainerElement
is empty, it is still displayed as an empty element. This is invalid according to the schema: whenever the element InnerContainerElement
is in the XML, InnerNodeOne
is required too.
How do I construct my FOR XML PATH
query in such a way that the InnerContainerElement
is left out whenever it's empty?
回答1:
You need to make sure that the InnerContainerElement
has zero rows for the case when there is no content.
select T.NumberNode,
T.FormattedNumberNode,
(
select T.InnerNodeOne,
T.InnerNodeStartDate
where T.InnerNodeOne is not null or
T.InnerNodeStartDate is not null
for xml path('InnerContainerElement'), type
)
from #temporaryXMLStore as T
for xml path('OuterElement'), root('Root')
Or you could specify the element InnerContainerElement
as a part of a column alias.
select T.NumberNode,
T.FormattedNumberNode,
T.InnerNodeOne as 'InnerContainerElement/InnerNodeOne',
T.InnerNodeStartDate as 'InnerContainerElement/InnerNodeStartDate'
from #temporaryXMLStore as T
for xml path('OuterElement'), root('Root')
来源:https://stackoverflow.com/questions/13468748/delete-empty-xml-nodes-using-t-sql-for-xml-path