2015-10-31 5 views
1

У меня есть ответ SOAP и нужно импортировать в SQL Server почти все поля soapenv: Body googleing and testing Я строю этот запрос, который кажется рабочим , но это не совсем то, что я ищет:Полностью импортировать SOAP XML в SQL Server 2012

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 различных мыл, а некоторые имеют до 120 Fiels, я искал решения, которые сплющить все поля и импорт автоматически в относительной таблице withoud требуя указать все строки: учитывая, что я использую sqlServer 2012/2014, есть ли решение, или если нет, есть лучший/более быстрый способ, чем то, что я поддерживаю osed?

Второе: (если нет лучшего решения) , так как у меня есть много полей для импорта, до 120 для некоторых SOAP, а так как root всегда один и тот же, я хотел бы уменьшить длину, помещая в переменную первая часть пути так, чтобы иметь , например

@xDoc.value('('[email protected]+'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)') 

возвращает значение, в противном случае вызовет ошибку , но в некоторых мыл некоторые поля являются опциями, и поэтому не всегда присутствует: I пытался с

;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)') 
.... 

но возникает ошибка: правильная форма запроса?

Большое спасибо

Джо

ответ

1

Другой способ, чтобы получить результат имя-значение, установленное вместо столбцов, а затем вы можете работать с этим, как вы хотите. Если вы хотите получить результат в виде столбцов, вы можете, например, сохранить набор значений имени-значения в таблице temp и сделать динамический стержень данных.

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 снова.

The XQuery must return at most one value.

Это прекрасно, чтобы вернуть никакого значения, и в этом случае возвращаемое значение является NULL.

Update:

Если конечный результат вы ищете действительно одна строка со значениями в столбцах вам лучше не пользоваться, что вы уже выяснили. Это можно упростить, поставив путь, общий для всех значений, в предложении 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 это даст тот же самый результат, который у вас уже есть, только оптимизатор может исключить пару операторов из плана запросов, чтобы потенциально быстрее делать измельчение таким образом.

+0

OK это решение намного проще, чем мое, и получить практически все данные .. но слишком сложно для меня понять мои текущие знания, и я не знаю, как идти дальше, поэтому я испытываю соблазн попросить дальнейшую помощь , в глубину: для этого SOAP наиболее важные поля находятся внутри FeedbackDetail, в то время как у меня есть NULL: как получить эту информацию? С динамическим стержнем вы предложили? Могут дать некоторые дополнительные намеки? А как насчет того, чтобы избежать некоторых полей? что-то проще, чем 'WHERE TXvalue ('local-name (.)', 'nvarchar (100)') <> 'Версия' или' NOT IN ('', '') 'Наконец, как создать запрос динамического обновления ? – Joe

+0

Думаете, что одно решение для основной проблемы может быть интегрировано в функцию xQuery 'leaf-elements'? - это правильное направление? – Joe

+0

@Joe Ваш лучший выбор - это, вероятно, продолжение пути, на котором вы уже были. Я добавил способ построить этот запрос, немного отличающийся от того, что у вас есть, и, возможно, проще в форме. –