如何检索具有特定子节点的XML列的行?

时间:2016-12-19 18:29:16

标签: sql-server xml tsql

我在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结构中的位置。

1 个答案:

答案 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

的ID
SELECT 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;