【问题标题】:Fully Import SOAP XML into SQL Server 2012将 SOAP XML 完全导入 SQL Server 2012
【发布时间】:2016-01-31 20:34:19
【问题描述】:

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

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 个字段,我一直在寻找一种解决方案,它可以展平所有字段并在相关表中自动导入 无需指示所有行:考虑到我使用的是 sqlServer 2012/2014 是否有解决方案,或者如果没有,是否有比我建议的更好/更快的方法?

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

@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)')

返回一个值,否则引发错误 但在某些 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)')
....

但是会报错:哪个是正确的查询形式?

非常感谢

【问题讨论】:

    标签: tsql soap sql-server-2012 xquery


    【解决方案1】:

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

    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() 返回当前节点名称,text() 返回节点值。

    nodes() 分解 XML 并为 XML 中的每个匹配节点返回一行。

    // 对 XML 进行深度搜索

    * 是一个匹配任何节点的通配符。

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

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

    nodes() 函数中的表达式将通过深度搜索为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

    XQuery 最多只能返回一个值。

    不返回值是完全可以的,在这种情况下返回的值是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,它将给出完全相同的结果,因为您已经有了只有优化器可以从查询计划中排除几个运算符,因此以这种方式进行粉碎可能更快。

    【讨论】:

    • 好的,这个解决方案比我的要简单得多,并且可以获取几乎所有的数据。但是对于我目前的知识来说太复杂了,我不知道如何更进一步,所以我很想寻求进一步的帮助。 into deep:对于这个 SOAP,最重要的字段都在 FeedbackDetail 中,而我有一个 NULL:如何获取该详细信息?您建议使用动态支点?可以给一些进一步的提示吗?那么如何避开一些领域呢?比WHERE T.X.value('local-name(.)', 'nvarchar(100)')&lt;&gt;'Version'NOT IN ('','') 更简单的事情最后如何构建动态更新查询?
    • 是否认为主要问题的一种解决方案可以是集成 xQuery 功能leaf-elements?这是正确的方向吗?
    • @Joe 你最好的选择可能是继续你已经走的路。我添加了一种构建查询的方法,它与您所拥有的有点不同,而且形式可能更简单。
    • 您好。好吧,您的解决方案要好得多,如果我的技能允许,我想朝这个方向前进:我有大约 50 种不同的 SOAP,您的解决方案允许我只为每个 SOAP 编写一个例程而不是一个例程。但需要得到如果节点具有子节点,则为最后一个子节点的 text():必须有一种方法来实现这一点.. 只需要找到它..
    • 仍然在这里.. 我添加了[count(child::*) = 0] ad end of from 以避免 NULL 行.. 我想我几乎拥有我需要的所有东西.. 现在将致力于构建更新查询.. 谢谢很多!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-26
    • 2023-03-16
    • 2013-06-02
    • 1970-01-01
    • 2018-05-06
    • 1970-01-01
    • 2013-05-27
    相关资源
    最近更新 更多