SQL Server WHERE子句具有多个节点和条件的XPath

时间:2017-01-10 15:50:58

标签: sql-server xml xpath

我在SQL Server的表列中有这个XML:

<root>
    <Request>
        <RequestData>
            <VendorLeadList>
                <VendorLeadItem>
                    <CampaignOfferTypeID>REN</CampaignOfferTypeID>
                    <LeadDispositionID>Lead</LeadDispositionID>
                    <Jurisdiction>NY</Jurisdiction>
                    <FirstName>Shikasta</FirstName>
                    <LastName>Kashti</LastName>
                    <MessageId>1347_1483825159115_c8273</MessageId>
                </VendorLeadItem>
            </VendorLeadList>
        </RequestData>
        <DualMessageID/>
        <AzureBlobFile/>
        <AzureBlobImageList/>
    </Request>
</root>

我想查询与某些节点匹配的具有特定值的所有记录。例如,我想要存在LeadDispositionID=LeadJurisdiction=NY以及CampaignOfferTypeID=RENMessageId元素的所有记录(并不重要。)

我尝试了这个但它不起作用(没有错误,但条件不匹配,它返回其他记录):

SELECT TOP 10 *
  FROM [Messages]
  WHERE PayLoadXml.exist('//LeadDispositionID[.="Lead"] and //CampaignOfferTypeID[.="REN"] and //Jurisdiction[.="NY"] and //MessageId') = 1
  ORDER BY ID DESC

知道我做错了什么?

1 个答案:

答案 0 :(得分:1)

您无法简单地将.exist()中的节点与and合并。你自己的例子会这样:

SELECT TOP 10 *
FROM @Messages
WHERE PayLoadXml.exist('//VendorLeadItem[LeadDispositionID[.="Lead"] and CampaignOfferTypeID[.="REN"] and Jurisdiction[.="NY"] and MessageId/text()]') = 1

试试这样:

首先将一个声明的表发送到模拟你的Messages表。插入3个案例:

DECLARE @messages TABLE(SomeDescription VARCHAR(100),PayLoadXml XML);
INSERT INTO @messages VALUES
('Your example'
,'<root>
    <Request>
        <RequestData>
            <VendorLeadList>
                <VendorLeadItem>
                    <CampaignOfferTypeID>REN</CampaignOfferTypeID>
                    <LeadDispositionID>Lead</LeadDispositionID>
                    <Jurisdiction>NY</Jurisdiction>
                    <FirstName>Shikasta</FirstName>
                    <LastName>Kashti</LastName>
                    <MessageId>1347_1483825159115_c8273</MessageId>
                </VendorLeadItem>
            </VendorLeadList>
        </RequestData>
        <DualMessageID/>
        <AzureBlobFile/>
        <AzureBlobImageList/>
    </Request>
</root>'
)
,('LeadDispositionID=Slave'
,'<root>
    <Request>
        <RequestData>
            <VendorLeadList>
                <VendorLeadItem>
                    <CampaignOfferTypeID>REN</CampaignOfferTypeID>
                    <LeadDispositionID>Slave</LeadDispositionID>
                    <Jurisdiction>NY</Jurisdiction>
                    <FirstName>Bruno</FirstName>
                    <LastName>Kashti</LastName>
                    <MessageId>1347_1483825159115_c8273</MessageId>
                </VendorLeadItem>
            </VendorLeadList>
        </RequestData>
        <DualMessageID/>
        <AzureBlobFile/>
        <AzureBlobImageList/>
    </Request>
</root>'
)
,('LeadDispositionID=Lead but No MessageId'
,'<root>
    <Request>
        <RequestData>
            <VendorLeadList>
                <VendorLeadItem>
                    <CampaignOfferTypeID>REN</CampaignOfferTypeID>
                    <LeadDispositionID>Lead</LeadDispositionID>
                    <Jurisdiction>NY</Jurisdiction>
                    <FirstName>Bruno</FirstName>
                    <LastName>Kashti</LastName>
                    <MessageId></MessageId>
                </VendorLeadItem>
            </VendorLeadList>
        </RequestData>
        <DualMessageID/>
        <AzureBlobFile/>
        <AzureBlobImageList/>
    </Request>
</root>'
);

这是查询: CROSS APPLY将确保仅考虑具有MessageId的节点。 WHERE将应用其他过滤器

SELECT m.*
FROM @messages AS m
CROSS APPLY m.PayLoadXml.nodes(N'/root/Request/RequestData/VendorLeadList/VendorLeadItem[not(empty(MessageId/text()))]') AS A(itm)
WHERE itm.exist(N'LeadDispositionID[text()="Lead"]')=1

如果您需要检查多个条件,可以使用它:

WHERE itm.exist(N'.[LeadDispositionID="Slave" and FirstName="Bruno"]')=1