将 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 它会给出与您已经拥有的结果完全相同的结果,只是优化器可以从查询计划中排除几个运算符,因此以这种方式进行分解可能会更快。
我有一个 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
*
是通配符,匹配任意节点。
[]
用于 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 它会给出与您已经拥有的结果完全相同的结果,只是优化器可以从查询计划中排除几个运算符,因此以这种方式进行分解可能会更快。