根据兄弟值查询 XML 数据以获取信息
Query XML data for information based on a sibling value
我有以下 XML 数据,我对这些数据的控制为零。请注意,它基本上是 属性 组的集合。我需要 select 一个 属性 的值,而另一个 属性 的值是 'true'。问题是,没有什么可以分组的,我不知道如何正确地关联事物。
这是 XML 数据,以及到目前为止我提出的查询:
DECLARE @xml xml = '
<Container>
<Collection>
<ItemName>SomeItem</ItemName>
<IsDeletable>true</IsDeletable>
<IsPersisted>false</IsPersisted>
</Collection>
<Collection>
<ItemName>AnotherItem</ItemName>
<IsDeletable>true</IsDeletable>
<IsPersisted>true</IsPersisted>
<ExistsInDB>true</ExistsInDB>
</Collection>
<Collection>
<ItemName>ItemFoo</ItemName>
<IsDeletable>true</IsDeletable>
<IsPersisted>true</IsPersisted>
<ExistsInDB>true</ExistsInDB>
</Collection>
<Collection>
<ItemName>BarBazItem</ItemName>
<IsDeletable>true</IsDeletable>
<IsPersisted>true</IsPersisted>
<ExistsInDB>false</ExistsInDB>
</Collection>
</Container>
'
;WITH XmlStuff AS (
SELECT CAST(xmlShredded.colXmlItem.query('local-name(.)') AS nvarchar(4000)) as XmlNodeName,
xmlShredded.colXmlItem.value('.', 'nvarchar(4000)') AS XmlNodeValue
FROM @xml.nodes('/*/Collection/child::node()') as xmlShredded(colXmlItem)
)
SELECT *
FROM XmlStuff
现在,我需要做的是为 "ExistsInDB" 为 'true' 的每个分组获取 "ItemName" 值。请注意 "ExistsInDB" 属性 在第一个 属性 集合中不存在(即它应该被视为 NULL/false)。
所以在这种情况下,我需要查询此 xml 数据,并取回以下集合:
另一个项目
ItemFoo
我不应该得到 "SomeItem" 或 "BarBazItem"。
我一直在拼命想弄清楚如何为 "Get all ItemName values where the associated ExistsInDB value is both present, and true".
制定查询
这可能吗?
嗨,也许尝试兄弟姐妹匹配
/Container/Collection/ItemName[../ExistsInDB='true']
获取其父项包含等于 "true".
的 ExistsInDb 子项的 ItemName 元素
DECLARE @xml xml = '
<Container>
<Collection>
<ItemName>SomeItem</ItemName>
<IsDeletable>true</IsDeletable>
<IsPersisted>false</IsPersisted>
</Collection>
<Collection>
<ItemName>AnotherItem</ItemName>
<IsDeletable>true</IsDeletable>
<IsPersisted>true</IsPersisted>
<ExistsInDB>true</ExistsInDB>
</Collection>
<Collection>
<ItemName>ItemFoo</ItemName>
<IsDeletable>true</IsDeletable>
<IsPersisted>true</IsPersisted>
<ExistsInDB>true</ExistsInDB>
</Collection>
<Collection>
<ItemName>BarBazItem</ItemName>
<IsDeletable>true</IsDeletable>
<IsPersisted>true</IsPersisted>
<ExistsInDB>false</ExistsInDB>
</Collection>
</Container>
';
SELECT node.value('.', 'nvarchar(100)')
FROM @xml.nodes('/Container/Collection/ItemName[../ExistsInDB="true"]') AS x(node)
您可以使用:
;WITH XmlStuff AS (
SELECT CAST(xmlShredded.colXmlItem.query('local-name(.)') AS nvarchar(4000)) as XmlNodeName,
xmlShredded.colXmlItem.value('.', 'nvarchar(4000)') AS XmlNodeValue,
xmlShredded.colXmlItem.value('(../ExistsInDB)[1]', 'nvarchar(4000)') AS ExistsInDB
FROM @xml.nodes('/*/Collection/child::node()') as xmlShredded(colXmlItem)
)
SELECT *
FROM XmlStuff
WHERE ExistsInDB = 'true';
你的预期输出有点烦人,因为你两次提到BarBazItem
So in this case, I need to query this xml data, and get back the
following set:
AnotherItem ItemFoo BarBazItem
I should NOT get "SomeItem" or "BarBazItem".
现有的两个答案都使用 backward-navigation(parent-axis 通过 ../
)。这是非常糟糕的表现(查找详细信息 here)并且不是最适合您的方法。试试这个:
SELECT nd.value('(ItemName/text())[1]','nvarchar(100)') AS ItemName
FROM @xml.nodes('/Container/Collection[ExistsInDB/text()="true"]') A(nd);
想法是,将谓词放在 <Collection>
之后的一级。您可以将其解读为
- 深入
<Container>
- 深入
<Collection>
,但我们只需要节点,其中有一个 text()
为“true”的子节点 <ExistsInDB>
。
- 由
A
编辑的列表 return 将包含每个 <Collection>
填充谓词(=过滤器) 的一行
.value()
-方法现在将在 <Collection>
<ItemName>
和 return text()
-节点下方的第一级。
我的查询 returns AnotherItem 和 ItemFoo
SomeItem 没有 returned 因为没有 <ExistsInDB>
和 BarBazItem 没有 returned 因为 <ExistsInDB>
.
中有“false”
更新
Lukasz Szoda 添加了 fiddle 并进行了一些改进。我认为最容易阅读 所有内容 的是:
SELECT nd.value('(ItemName/text())[1]','nvarchar(100)') AS ItemName
,nd.value('(IsDeletable/text())[1]','bit') AS IsDeletable
,nd.value('(IsPersisted/text())[1]','bit') AS IsPersisted
FROM @xml.nodes('/Container/Collection[ExistsInDB/text()="true"]') A(nd);
我有以下 XML 数据,我对这些数据的控制为零。请注意,它基本上是 属性 组的集合。我需要 select 一个 属性 的值,而另一个 属性 的值是 'true'。问题是,没有什么可以分组的,我不知道如何正确地关联事物。
这是 XML 数据,以及到目前为止我提出的查询:
DECLARE @xml xml = '
<Container>
<Collection>
<ItemName>SomeItem</ItemName>
<IsDeletable>true</IsDeletable>
<IsPersisted>false</IsPersisted>
</Collection>
<Collection>
<ItemName>AnotherItem</ItemName>
<IsDeletable>true</IsDeletable>
<IsPersisted>true</IsPersisted>
<ExistsInDB>true</ExistsInDB>
</Collection>
<Collection>
<ItemName>ItemFoo</ItemName>
<IsDeletable>true</IsDeletable>
<IsPersisted>true</IsPersisted>
<ExistsInDB>true</ExistsInDB>
</Collection>
<Collection>
<ItemName>BarBazItem</ItemName>
<IsDeletable>true</IsDeletable>
<IsPersisted>true</IsPersisted>
<ExistsInDB>false</ExistsInDB>
</Collection>
</Container>
'
;WITH XmlStuff AS (
SELECT CAST(xmlShredded.colXmlItem.query('local-name(.)') AS nvarchar(4000)) as XmlNodeName,
xmlShredded.colXmlItem.value('.', 'nvarchar(4000)') AS XmlNodeValue
FROM @xml.nodes('/*/Collection/child::node()') as xmlShredded(colXmlItem)
)
SELECT *
FROM XmlStuff
现在,我需要做的是为 "ExistsInDB" 为 'true' 的每个分组获取 "ItemName" 值。请注意 "ExistsInDB" 属性 在第一个 属性 集合中不存在(即它应该被视为 NULL/false)。
所以在这种情况下,我需要查询此 xml 数据,并取回以下集合:
另一个项目 ItemFoo
我不应该得到 "SomeItem" 或 "BarBazItem"。
我一直在拼命想弄清楚如何为 "Get all ItemName values where the associated ExistsInDB value is both present, and true".
制定查询这可能吗?
嗨,也许尝试兄弟姐妹匹配
/Container/Collection/ItemName[../ExistsInDB='true']
获取其父项包含等于 "true".
的 ExistsInDb 子项的 ItemName 元素DECLARE @xml xml = '
<Container>
<Collection>
<ItemName>SomeItem</ItemName>
<IsDeletable>true</IsDeletable>
<IsPersisted>false</IsPersisted>
</Collection>
<Collection>
<ItemName>AnotherItem</ItemName>
<IsDeletable>true</IsDeletable>
<IsPersisted>true</IsPersisted>
<ExistsInDB>true</ExistsInDB>
</Collection>
<Collection>
<ItemName>ItemFoo</ItemName>
<IsDeletable>true</IsDeletable>
<IsPersisted>true</IsPersisted>
<ExistsInDB>true</ExistsInDB>
</Collection>
<Collection>
<ItemName>BarBazItem</ItemName>
<IsDeletable>true</IsDeletable>
<IsPersisted>true</IsPersisted>
<ExistsInDB>false</ExistsInDB>
</Collection>
</Container>
';
SELECT node.value('.', 'nvarchar(100)')
FROM @xml.nodes('/Container/Collection/ItemName[../ExistsInDB="true"]') AS x(node)
您可以使用:
;WITH XmlStuff AS (
SELECT CAST(xmlShredded.colXmlItem.query('local-name(.)') AS nvarchar(4000)) as XmlNodeName,
xmlShredded.colXmlItem.value('.', 'nvarchar(4000)') AS XmlNodeValue,
xmlShredded.colXmlItem.value('(../ExistsInDB)[1]', 'nvarchar(4000)') AS ExistsInDB
FROM @xml.nodes('/*/Collection/child::node()') as xmlShredded(colXmlItem)
)
SELECT *
FROM XmlStuff
WHERE ExistsInDB = 'true';
你的预期输出有点烦人,因为你两次提到BarBazItem
So in this case, I need to query this xml data, and get back the following set:
AnotherItem ItemFoo BarBazItem
I should NOT get "SomeItem" or "BarBazItem".
现有的两个答案都使用 backward-navigation(parent-axis 通过 ../
)。这是非常糟糕的表现(查找详细信息 here)并且不是最适合您的方法。试试这个:
SELECT nd.value('(ItemName/text())[1]','nvarchar(100)') AS ItemName
FROM @xml.nodes('/Container/Collection[ExistsInDB/text()="true"]') A(nd);
想法是,将谓词放在 <Collection>
之后的一级。您可以将其解读为
- 深入
<Container>
- 深入
<Collection>
,但我们只需要节点,其中有一个text()
为“true”的子节点<ExistsInDB>
。 - 由
A
编辑的列表 return 将包含每个<Collection>
填充谓词(=过滤器) 的一行
.value()
-方法现在将在<Collection>
<ItemName>
和 returntext()
-节点下方的第一级。
我的查询 returns AnotherItem 和 ItemFoo
SomeItem 没有 returned 因为没有 <ExistsInDB>
和 BarBazItem 没有 returned 因为 <ExistsInDB>
.
更新
Lukasz Szoda 添加了 fiddle 并进行了一些改进。我认为最容易阅读 所有内容 的是:
SELECT nd.value('(ItemName/text())[1]','nvarchar(100)') AS ItemName
,nd.value('(IsDeletable/text())[1]','bit') AS IsDeletable
,nd.value('(IsPersisted/text())[1]','bit') AS IsPersisted
FROM @xml.nodes('/Container/Collection[ExistsInDB/text()="true"]') A(nd);