我在SQL Server中有一个带有XML列的表:
CREATE TABLE dbo.XmlData (
id INT IDENTITY,
data XML
);
存储在data
列中的XML是动态的,我的意思是,它们中只有一些具有某些子节点。此外,此节点出现在XML结构中的不同位置。
示例1,/RootNode/FindMe
:
<RootNode>
<ChildNodeOne>One</ChildNodeOne>
<ChildNodeTwo>Two</ChildNodeTwo>
<ChildNodeThree>Three</ChildNodeThree>
<FindMe>FindMe</FindMe>
</RootNode>
示例2,/RootNode/ChildNodeThree/Deeper/FindMe
和/RootNode/ChildNodeTwo/FindMe
:
<RootNode>
<ChildNodeOne>One</ChildNodeOne>
<ChildNodeTwo>
<FindMe>FindMe</FindMe>
</ChildNodeTwo>
<ChildNodeThree>
<Deeper>
<FindMe>FindMe</FindMe>
</Deeper>
</ChildNodeThree>
</RootNode>
XML列中的行没有<FindMe/>
节点。
我需要编写一个查询来仅检索具有<FindMe/>
节点的行。无论它在XML结构中的位置。
答案 0 :(得分:1)
首先要知道的是,//FindMe
会触发深度搜索。这意味着:在XML 中找到该节点。单个/
标记根元素(在开头开始搜索),no slash at all
标记当前节点(从上下文节点继续) :
以下是一些可以查询节点名称的示例:
用于测试的虚拟表:
CREATE TABLE dbo.DummyTbl (
id INT IDENTITY,
Remark VARCHAR(100),
data XML
);
INSERT INTO DummyTbl VALUES
('FindMe is on second level',
'<RootNode>
<ChildNodeOne>One</ChildNodeOne>
<ChildNodeTwo>Two</ChildNodeTwo>
<ChildNodeThree>Three</ChildNodeThree>
<FindMe>FindMe 1</FindMe>
</RootNode>')
,('FindMe is two times somewhere deeper',
'<RootNode>
<ChildNodeOne>One</ChildNodeOne>
<ChildNodeTwo>
<FindMe>FindMe 2a</FindMe>
</ChildNodeTwo>
<ChildNodeThree>
<Deeper>
<FindMe>FindMe 2b</FindMe>
</Deeper>
</ChildNodeThree>
</RootNode>')
,('FindMe does not exist',
'<RootNode>
<ChildNodeOne>One</ChildNodeOne>
<ChildNodeTwo>
</ChildNodeTwo>
<ChildNodeThree>
<Deeper>
<FindMeNot>Something else</FindMeNot>
</Deeper>
</ChildNodeThree>
</RootNode>')
,('FindMe exists, but is empty',
'<RootNode>
<ChildNodeOne>One</ChildNodeOne>
<ChildNodeTwo>
</ChildNodeTwo>
<ChildNodeThree>
<Deeper>
<FindMe/>
</Deeper>
</ChildNodeThree>
</RootNode>');
不同的查询:
- 所有FindMe节点(包括空节点)
SELECT d.id,d.Remark
,f.value('.','nvarchar(max)') FindMeNode
FROM dbo.DummyTbl AS d
CROSS APPLY d.data.nodes('//FindMe') AS A(f)
- 所有至少有一个“FindMe”-node
的IDSELECT d.id,d.Remark
FROM dbo.DummyTbl AS d
WHERE d.data.exist('//FindMe')=1
GO
- 所有至少有一个“FindMe”节点的ID,而不是空的
SELECT d.id,d.Remark
FROM dbo.DummyTbl AS d
WHERE d.data.exist('//FindMe/text()')=1
- 查找ID,其中至少有一个空的FindMe节点
SELECT d.id,d.Remark
FROM dbo.DummyTbl AS d
WHERE d.data.exist('//FindMe[empty(text())]')=1
- 现在使用变量名称来搜索
DECLARE @SearchForName NVARCHAR(100)='FindMe';
SELECT d.id,d.Remark
FROM dbo.DummyTbl AS d
WHERE d.data.exist('//*[local-name()=sql:variable("@SearchForName")]/text()')=1
GO
- 清理
DROP TABLE dbo.DummyTbl;