将 SOAP XML 完全导入 SQL Server 2012

Fully Import SOAP XML into SQL Server 2012

我有一个 SOAP 响应,需要将 soapenv:Body 的几乎所有字段导入 SQL 服务器 谷歌搜索和测试我构建了这个似乎有效的查询 但这并不是我要找的:

declare 
@Root varchar(50)='/soap:Envelope/soap:Body/GetFeedbackResponse/', 
@xDoc XML = '<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soapenv:Header>
        <ebl:RequesterCredentials soapenv:mustUnderstand="0" xmlns:ns="urn:ebay:apis:eBLBaseComponents" xmlns:ebl="urn:ebay:apis:eBLBaseComponents">
            <ebl:NotificationSignature xmlns:ebl="urn:ebay:apis:eBLBaseComponents">r6revSiTXCP9SBBFUtpDAQ==</ebl:NotificationSignature>
        </ebl:RequesterCredentials>
    </soapenv:Header>
    <soapenv:Body>
        <GetFeedbackResponse xmlns="urn:ebay:apis:eBLBaseComponents">
            <Timestamp>2015-09-06T11:20:48.528Z</Timestamp>
            <Ack>Success</Ack>
            <CorrelationID>428163922470</CorrelationID>
            <Version>899</Version>
            <Build>E899_INTL_APIFEEDBACK_17278558_R1</Build>
            <NotificationEventName>Feedback</NotificationEventName>
            <RecipientUserID>ebay_bestseller</RecipientUserID>
            <EIASToken>nY+sHZ2PrBmdj6wVnY+sEWDETj2dj6AFlIajDpaEpAydj6x9nY+seQ==</EIASToken>
            <FeedbackDetailArray>
                <FeedbackDetail>
                    <CommentingUser>ebay_bestseller</CommentingUser>
                    <CommentingUserScore>42425</CommentingUserScore>
                    <CommentText>Great buyer - We Would Appreciate 5 STARS for Our Feedback!</CommentText>
                    <CommentTime>2015-09-06T11:20:45.000Z</CommentTime>
                    <CommentType>Positive</CommentType>
                    <ItemID>310541589307</ItemID>
                    <Role>Buyer</Role>
                    <FeedbackID>1064451206013</FeedbackID>
                    <TransactionID>549674542021</TransactionID>
                    <OrderLineItemID>310541589307-549674542021</OrderLineItemID>
                </FeedbackDetail>
            </FeedbackDetailArray>
            <FeedbackDetailItemTotal>1</FeedbackDetailItemTotal>
            <FeedbackScore>126</FeedbackScore>
            <PaginationResult>
                <TotalNumberOfPages>1</TotalNumberOfPages>
                <TotalNumberOfEntries>1</TotalNumberOfEntries>
            </PaginationResult>
            <EntriesPerPage>25</EntriesPerPage>
            <PageNumber>1</PageNumber>
        </GetFeedbackResponse>
    </soapenv:Body>
</soapenv:Envelope>'

;with xmlnamespaces('http://schemas.xmlsoap.org/soap/envelope/' as [soap], default 'urn:ebay:apis:eBLBaseComponents')
insert into Test (TS,Comment) 
select 
@xDoc.value('(/soap:Envelope/soap:Body/GetFeedbackResponse/Timestamp)[1]', 'nvarchar(max)'),
@xDoc.value('(/soap:Envelope/soap:Body/GetFeedbackResponse/FeedbackDetailArray/FeedbackDetail/CommentText)[1]', 'nvarchar(max)'),
........

第一个问题:由于有大约 50 个不同的 SOAP 响应,有些确实有多达 120 个字段,我一直在寻找一种解决方案,它可以展平所有字段并自动导入相关 table 不需要指示所有行:考虑到我使用的是 sqlServer 2012/2014 是否有解决方案,或者如果没有,是否有 better/quicker 比我建议的方法?

其二:(如果没有更好的解决办法) 因为我有很多字段要导入,一些 SOAP 最多 120 个,并且由于根总是相同的,所以我想减少在路径的第一部分中放入变量的长度,以便 例如

@xDoc.value('('+@Root+'Timestamp)[1]', 'nvarchar(max)')

而不是

@xDoc.value('(/soap:Envelope/soap:Body/GetFeedbackResponse/Timestamp)[1]', 'nvarchar(max)')

但我收到一个错误,例如第一个值必须是字面值:是否有任何转机?

第三:来自文档...要求查询

@xDoc.value('(/soap:Envelope/soap:Body/GetFeedbackResponse/Timestamp)[1]', 'nvarchar(max)')

returns 一个值,否则报错 但在某些 SOAP 中,某些字段是可选的,因此并不总是存在: 我试过

;with xmlnamespaces('http://schemas.xmlsoap.org/soap/envelope/' as [soap], default 'urn:ebay:apis:eBLBaseComponents')
insert into Test (TS,Comment) 
select if (exists @xDoc.value('(/soap:Envelope/soap:Body/GetFeedbackResponse/Timestamp)')) then @xDoc.value('(/soap:Envelope/soap:Body/GetFeedbackResponse/Timestamp)[1]', 'nvarchar(max)')
....

但出现错误:哪个是正确的查询形式?

非常感谢

另一种方法是获取名称-值结果集而不是列,然后您可以根据需要使用它。如果您希望结果作为列,您可以将名称-值结果集存储在临时 table 中,并对数据进行动态透视。

declare 
@Root varchar(50)='GetFeedbackResponse', 
@xDoc XML = '<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soapenv:Header>
        <ebl:RequesterCredentials soapenv:mustUnderstand="0" xmlns:ns="urn:ebay:apis:eBLBaseComponents" xmlns:ebl="urn:ebay:apis:eBLBaseComponents">
            <ebl:NotificationSignature xmlns:ebl="urn:ebay:apis:eBLBaseComponents">r6revSiTXCP9SBBFUtpDAQ==</ebl:NotificationSignature>
        </ebl:RequesterCredentials>
    </soapenv:Header>
    <soapenv:Body>
        <GetFeedbackResponse xmlns="urn:ebay:apis:eBLBaseComponents">
            <Timestamp>2015-09-06T11:20:48.528Z</Timestamp>
            <Ack>Success</Ack>
            <CorrelationID>428163922470</CorrelationID>
            <Version>899</Version>
            <Build>E899_INTL_APIFEEDBACK_17278558_R1</Build>
            <NotificationEventName>Feedback</NotificationEventName>
            <RecipientUserID>ebay_bestseller</RecipientUserID>
            <EIASToken>nY+sHZ2PrBmdj6wVnY+sEWDETj2dj6AFlIajDpaEpAydj6x9nY+seQ==</EIASToken>
            <FeedbackDetailArray>
                <FeedbackDetail>
                    <CommentingUser>ebay_bestseller</CommentingUser>
                    <CommentingUserScore>42425</CommentingUserScore>
                    <CommentText>Great buyer - We Would Appreciate 5 STARS for Our Feedback!</CommentText>
                    <CommentTime>2015-09-06T11:20:45.000Z</CommentTime>
                    <CommentType>Positive</CommentType>
                    <ItemID>310541589307</ItemID>
                    <Role>Buyer</Role>
                    <FeedbackID>1064451206013</FeedbackID>
                    <TransactionID>549674542021</TransactionID>
                    <OrderLineItemID>310541589307-549674542021</OrderLineItemID>
                </FeedbackDetail>
            </FeedbackDetailArray>
            <FeedbackDetailItemTotal>1</FeedbackDetailItemTotal>
            <FeedbackScore>126</FeedbackScore>
            <PaginationResult>
                <TotalNumberOfPages>1</TotalNumberOfPages>
                <TotalNumberOfEntries>1</TotalNumberOfEntries>
            </PaginationResult>
            <EntriesPerPage>25</EntriesPerPage>
            <PageNumber>1</PageNumber>
        </GetFeedbackResponse>
    </soapenv:Body>
</soapenv:Envelope>'

select T.X.value('local-name(.)', 'nvarchar(100)') as Name,
       T.X.value('text()[1]', 'nvarchar(100)') as Value
from @xDoc.nodes('//*[local-name(.) = sql:variable("@Root")]//*') as T(X)

local-name() returns 当前节点名称和 text() returns 节点值。

nodes() 为 XML.

中的每个匹配节点将 XML 和 return 切碎一行

// 深入搜索 XML

*是通配符,匹配任意节点。

[] 用于 xQuery 表达式中的谓词。

sql:variable() 是一个将变量值提取到 xQuery 中的函数。您不能使用 sql:variable() 来构建 xQuery 表达式。

nodes() 函数中的表达式将 return 下面的每个元素一行 GetFeedbackResponse 进行深度搜索。

结果:

Name                      Value
------------------------- -----------------------------------------------
Timestamp                 2015-09-06T11:20:48.528Z
Ack                       Success
CorrelationID             428163922470
Version                   899
Build                     E899_INTL_APIFEEDBACK_17278558_R1
NotificationEventName     Feedback
RecipientUserID           ebay_bestseller
EIASToken                 nY+sHZ2PrBmdj6wVnY+sEWDETj2dj6AFlIajDpaEpAydj6x9nY+seQ==
FeedbackDetailArray       NULL
FeedbackDetail            NULL
CommentingUser            ebay_bestseller
CommentingUserScore       42425
CommentText               Great buyer - We Would Appreciate 5 STARS for Our Feedback!
CommentTime               2015-09-06T11:20:45.000Z
CommentType               Positive
ItemID                    310541589307
Role                      Buyer
FeedbackID                1064451206013
TransactionID             549674542021
OrderLineItemID           310541589307-549674542021
FeedbackDetailItemTotal   1
FeedbackScore             126
PaginationResult          NULL
TotalNumberOfPages        1
TotalNumberOfEntries      1
EntriesPerPage            25
PageNumber                1

第三个:

你应该再读一遍docs

The XQuery must return at most one value.

return 没有值是完全没问题的,在这种情况下 returned 的值是 NULL

更新:

如果您要寻找的最终结果确实是一行,列中有值,您最好使用您已经知道的结果。通过将所有值的公共路径放在 nodes() 子句中,可以稍微简化它。像这样。

with xmlnamespaces('http://schemas.xmlsoap.org/soap/envelope/' as [soap], default 'urn:ebay:apis:eBLBaseComponents')
select T.X.value('(Timestamp/text())[1]', 'datetime') as Timestamp,
       T.X.value('(Ack/text())[1]', 'varchar(10)') as Ack,
       T.X.value('(CorrelationID/text())[1]', 'varchar(20)') as CorrelationID
from @xDoc.nodes('/soap:Envelope/soap:Body/GetFeedbackResponse') as T(X)

只需添加您实际需要的额外列即可。我还在从节点提取值的位置添加了 /text()。对于您 XML 它会给出与您已经拥有的结果完全相同的结果,只是优化器可以从查询计划中排除几个运算符,因此以这种方式进行分解可能会更快。