简体   繁体   English

如何返回SQL Server XPath中存在的值?

[英]How to return the value that exists in SQL Server XPath?

There is a question somewhere on Stackoverflow, although i cannot find it now, that reminded the poster that .value does not return the value that .exist s. 在Stackoverflow上的某个地方有一个问题,尽管我现在找不到,但提醒发布者.value不会返回.exist s的值。

That is because .value is always written as asking for the [1] item, where .exist looks everywhere. 这是因为.value始终写为要求[1]项,而.exist到处都是。

Example

Given a hypothetical xml document containing two customers: 给定一个假设的xml文档,其中包含两个客户:

<Customer>
    <Name>Ian Boyd</Name>
    <IDInfo>
        <IDType>1</IDType>
    </IDInfo>
</Customer>
<Customer>
    <Name>Kirsten</Name>
    <IDInfo>
        <IDType>3</IDType>
        <IDOtherDescription>Firearms Certificate</IDOtherDescription>
    </IDInfo>
</Customer>

i want to return the Name , IDType , and IDOtherDescription for any customers who have an IDType of 3 (Other): 我想为IDType3 (其他)的任何客户返回NameIDTypeIDOtherDescription

DECLARE @xml XML;
SET @xml = 
'<Customer>
    <Name>Ian Boyd</Name>
    <IDInfo>
        <IDType>1</IDType>
    </IDInfo>
</Customer>
<Customer>
    <Name>Kirsten</Name>
    <IDInfo>
        <IDType>3</IDType>
        <IDOtherDescription>Firearms Certificate</IDOtherDescription>
    </IDInfo>
</Customer>'
--Wrap it up in a table, cause it makes it look more like my real situation
;WITH BatchReports AS (
    SELECT @xml AS BatchFileXml
)
SELECT
    BatchFileXml.value('(//Name)[1]', 'varchar(50)') AS Name,
    BatchFileXml.value('(//IDType)[1]', 'varchar(50)') AS IDType,
    BatchFileXml.value('(//IDOtherDescription)[1]', 'varchar(50)') AS IDOtherDescription,
    *
FROM BatchReports
--WHERE BatchFileXml.value('(//IDType)[1]', 'varchar(50)') = '3'
WHERE BatchFileXml.exist('//IDType[text()="3"]')=1

Since the .exist is satisfied, it returns a row: 由于.exist 满足 ,它返回一行:

Name     IDType IDOtherDescription
-------- ------ --------------------
Ian Boyd      1 Firearms Certificate

Except that's not what i wanted. 除非那不是我想要的。 I wanted the values where IDType = 3 . 我想要IDType = 3的值。

Things get even more complicated, where there are multiple IDType entries: 在有多个IDType条目的情况下,事情变得更加复杂:

<Customer>
    <Name>Ian Boyd</Name>
    <IDInfo>
        <IDType>1</IDType>
    </IDInfo>
</Customer>
<Customer>
    <Name>Kirsten</Name>
    <IDInfo>
        <IDType>1</IDType>
    </IDInfo>
    <IDInfo>
        <IDType>2</IDType>
    </IDInfo>
    <IDInfo>
        <IDType>4</IDType>
    </IDInfo>
    <IDInfo>
        <IDType>3</IDType>
        <IDOtherDescription>Firearms Certificate</IDOtherDescription>
    </IDInfo>
</Customer>

And even more complicated when you can find /IDInfo nodes in other levels: 在其他级别可以找到/IDInfo节点时,甚至更加复杂:

<Customer>
    <Name>Ian Boyd</Name>
    <IDInfo>
        <IDType>1</IDType>
    </IDInfo>
    <ThirdPartyInfo>
       <IDInfo>
        <IDType>3</IDType>
            <IDOtherDescription>Sherrif Badge</IDOtherDescription>
       </IDInfo>
    </ThirdPartyInfo>
</Customer>
<Customer>
    <Name>Kirsten</Name>
    <IDInfo>
        <IDType>1</IDType>
    </IDInfo>
    <IDInfo>
        <IDType>2</IDType>
    </IDInfo>
    <IDInfo>
        <IDType>4</IDType>
    </IDInfo>
    <IDInfo>
        <IDType>3</IDType>
        <IDOtherDescription>Firearms Certificate</IDOtherDescription>
    </IDInfo>
</Customer>

The end result is the same. 最终结果是相同的。 I need a query to return the values that exist : 我需要一个查询以返回existvalues

Name     IDType IDOtherDescription
-------- ------ --------------------
Ian Boyd      3 Sherrif Badge
Kirsten       3 Firearms Certificate

Bonus Chatter 奖金Chat不休

When i designed the system two years ago, and chose to use XML data type, i figured it would be useful when there's an emergency. 当我两年前设计系统并选择使用XML数据类型时,我认为在紧急情况下它将很有用。 I can use some XPath to filter through the raw xml. 我可以使用一些XPath来过滤原始xml。 I forgot how impossible XPath, and XPath in SQL Server is. 我忘记了XPath和SQL Server中的XPath是多么不可能。 Four hours of staring at documentation and web-sites; 盯着文档和网站四个小时; i'm hungry and tired. 我饿又累。

Here is the query you can try: 您可以尝试以下查询:

;WITH BatchReports AS (
    SELECT @xml AS BatchFileXml
)
SELECT a.BatchXml.value('(Name)[1]', 'varchar(50)') AS Name,
    a.BatchXml.value('(IDInfo/IDType)[1]', 'varchar(50)') AS IDType,
    a.BatchXml.value('(IDInfo/IDOtherDescription)[1]', 'varchar(50)') AS IDOtherDescription
FROM BatchReports b
CROSS APPLY b.BatchFileXml.nodes('Customer') A(BatchXml)
WHERE a.BatchXml.exist('IDInfo/IDType[text()=3]')=1

and here is the query which retrieve necessary information form all of the XMLs. 这是从所有XML中检索必要信息的查询。

;WITH BatchReports AS (
    SELECT @xml AS BatchFileXml
)
SELECT A.BatchXml.value('(Name)[1]', 'varchar(50)') AS Name,
    B.BatchXml.value('(IDType)[1]', 'varchar(50)') AS IDType,
    B.BatchXml.value('(IDOtherDescription)[1]', 'varchar(50)') AS IDOtherDescription
FROM BatchReports X
CROSS APPLY X.BatchFileXml.nodes('Customer') A(BatchXml)
CROSS APPLY A.BatchXml.nodes('//IDInfo') B(BatchXml)
WHERE A.BatchXml.exist('IDInfo/IDType[text()=3]')=1
    AND B.BatchXml.exist('IDType[text()=3]')=1

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM