2012-04-03 3 views
2

Я использую возможности XML-синтаксического анализа SQL Server 2008 для итерации через XML-документ и выполнения INSERT каждого элемента.Использование OPENXML в SQL Server 2008 сохраненный порядок proc-INSERT отличается от XML-документа

Однако моя хранимая процедура, кажется, вставляет каждый элемент в таблицу в порядке, который отличается от порядка в документе.

Кроме того, чем больше раз я пытаюсь это сделать, порядок INSERT, похоже, меняется.

Вот пример XML-документа - здесь нет ничего необычного.

<ts> 
    <t id="36a3c8c1-b958-42f0-82d1-dfa6bf9b99a1" encryptedAccountId="fQ/XF8lpeR9wEDUV3yMzvQ==" uploaded="2012-04-03T15:49:19.9615097Z" visible="1"> 
     <tv fieldId="301" officialValue="0, 0" friendlyValue="0, 0" /> 
     <tv fieldId="302" officialValue="0, 1" friendlyValue="0, 1" /> 
     <tv fieldId="303" officialValue="0, 2" friendlyValue="0, 2" /> 
     <tv fieldId="304" officialValue="0, 3" friendlyValue="0, 3" /> 
     <tv fieldId="305" officialValue="0, 4" friendlyValue="0, 4" /> 
     <tv fieldId="306" officialValue="0, 5" friendlyValue="0, 5" /> 
    </t> 
    <t id="9d56d082-4b6a-4bdf-a7a2-f5c6af88344e" encryptedAccountId="fQ/XF8lpeR9wEDUV3yMzvQ==" uploaded="2012-04-03T15:49:19.9615097Z" visible="1"> 
     <tv fieldId="301" officialValue="1, 0" friendlyValue="1, 0" /> 
     <tv fieldId="302" officialValue="1, 1" friendlyValue="1, 1" /> 
     <tv fieldId="303" officialValue="1, 2" friendlyValue="1, 2" /> 
     <tv fieldId="304" officialValue="1, 3" friendlyValue="1, 3" /> 
     <tv fieldId="305" officialValue="1, 4" friendlyValue="1, 4" /> 
     <tv fieldId="306" officialValue="1, 5" friendlyValue="1, 5" /> 
    </t> 
    <t id="27db47a3-ad3f-4279-8f4f-0a8944ce32d4" encryptedAccountId="fQ/XF8lpeR9wEDUV3yMzvQ==" uploaded="2012-04-03T15:49:19.9615097Z" visible="1"> 
     <tv fieldId="301" officialValue="2, 0" friendlyValue="2, 0" /> 
     <tv fieldId="302" officialValue="2, 1" friendlyValue="2, 1" /> 
     <tv fieldId="303" officialValue="2, 2" friendlyValue="2, 2" /> 
     <tv fieldId="304" officialValue="2, 3" friendlyValue="2, 3" /> 
     <tv fieldId="305" officialValue="2, 4" friendlyValue="2, 4" /> 
     <tv fieldId="306" officialValue="2, 5" friendlyValue="2, 5" /> 
    </t> 
    <t id="867ea26b-0341-4d60-ac48-f305492a60f0" encryptedAccountId="fQ/XF8lpeR9wEDUV3yMzvQ==" uploaded="2012-04-03T15:49:19.9615097Z" visible="1"> 
     <tv fieldId="301" officialValue="3, 0" friendlyValue="3, 0" /> 
     <tv fieldId="302" officialValue="3, 1" friendlyValue="3, 1" /> 
     <tv fieldId="303" officialValue="3, 2" friendlyValue="3, 2" /> 
     <tv fieldId="304" officialValue="3, 3" friendlyValue="3, 3" /> 
     <tv fieldId="305" officialValue="3, 4" friendlyValue="3, 4" /> 
     <tv fieldId="306" officialValue="3, 5" friendlyValue="3, 5" /> 
    </t> 
</ts> 

Хранимая процедура имеет несколько операций, протекающие, но я закомментированная другие части, оставляя только SQL, который вставляет в <t/> элементы, а затем <tv/> элементы.

SQL в хранимой процедуре выглядит следующим образом.

(@xmlTransaction является NVARCHAR (MAX) входа парами, содержащих выше XML)

BEGIN 
    SET NOCOUNT ON; 

    DECLARE @encryptedAccountID AS VARCHAR(200) 

    BEGIN TRANSACTION 
     BEGIN TRY 
      DECLARE @Handle AS INT 
      DECLARE @TransactionCount AS INT 

      EXEC sp_xml_preparedocument @Handle OUTPUT, @xmlTransaction 

      /* encryptedAccountId is always the same for each @xmlTransaction param */ 
      /* Just take the value from the first <t/> element */ 
      SET @encryptedAccountID = (SELECT eID FROM OPENXML (@Handle, '/ts/t[1]', 2) WITH (eID VARCHAR '@encryptedAccountId')) 

      /* Go through each <t/> element in the XML document and INSERT */ 
      INSERT INTO 
      [Transactions] 
      (
       [ID], 
       [EncryptedAccountID] 
      ) 
      SELECT 
       * 
      FROM 
       OPENXML (@Handle, '/ts/t', 2) 
      WITH 
      (
       rID UNIQUEIDENTIFIER '@id', 
       rEncryptedAccountID VARCHAR (200) '@encryptedAccountId' 
      ) 

      /* Loop through each TransactionValue in the XML document and INSERT */ 
      INSERT INTO 
      [TransactionValues] 
      (
       FieldID, 
       TransactionID, 
       OfficialValue, 
       FriendlyValue 
      ) 
      SELECT 
       * 
      FROM 
       OPENXML (@Handle, '/ts/t/tv', 2) 
      WITH 
      (
       rFieldID INT '@fieldId', 
       rTransactionID UNIQUEIDENTIFIER '../@id', 
       rOfficialValue NVARCHAR (500) '@officialValue', 
       rFriendlyValue NVARCHAR (500) '@friendlyValue' 
      ) 

      /* Dispose of the XML document */ 
      EXEC sp_xml_removedocument @Handle 

     COMMIT TRANSACTION 
    END TRY 
    BEGIN CATCH 

     RETURN @@ERROR 

     ROLLBACK TRANSACTION   
    END CATCH 

END 

Должен быть довольно просто. И все же, если я запрашиваю результаты, они не совпадают с документом XML. Второй оператор INSERT для элементов <tv/>делает хранит элементы во второй таблице в правильном порядке, но элементы <t/>: не хранятся в таблице в правильном порядке.

Может ли кто-нибудь объяснить мне, почему элементы <t/> НЕ ВСТАВЛЯЕТСЯ в таблицу в том же порядке, что и в документе XML?

ответ

3

Если я использую встроенную поддержку XQuery в SQL Server вместо «устаревшего» OPENXML вещи, то, казалось бы, что <t> узлы действительно вставляются в таблицу в порядке они появляются в документе XML.

Я использовал код что-то вроде этого:

INSERT INTO dbo.[Transactions]([ID], [EncryptedAccountID]) 
    SELECT 
     XT.value('@id', 'uniqueidentifier'), 
     XT.value('@encryptedAccountId', 'varchar(200)') 
    FROM 
     @xmlTransaction.nodes('/ts/t') AS Nodes(XT) 

То же самое можно было бы сделать для <tv> подузлов тоже.

+2

Я совершенно не осведомлен об этом XQuery в SQL Server и думал, что OPENXML - единственный способ добиться этого. Теперь я буду исследовать XQuery и отчитаться. – awj

+0

Я потратил час, пытаясь заставить это работать, но не может. Я не могу найти никаких учебников или руководств с синтаксисом, подобным вашим - все страницы, которые я могу найти, относятся к тому, как изменять существующие поля XML. Я пробовал ваш SQL, но получаю сообщение «Узлы XMLDT-метода» могут быть вызваны только в столбцах типа xml ». Конечно, мне не нужно менять типы полей для вставки этих данных? Тем более, что вы все еще объявляли типы для «id» и «encryptedAccountId» [не разрешали использовать символ «at» в комментариях]. Вот скриншот того, что я пытался сделать: http://screencast.com/t/CToJqYqH55RH – awj

+0

В моем тестировании производительности openxml избили xquery огромным запасом. Зависит от вашего документа. Каждая колонка, которую вы запрашиваете с помощью xquery, создает таблицу, которая затем внутренне соединяется с каждым другим столбцом, чтобы дать вам таблицу. OpenXML - подборщик специальных символов. Я использую только xquery, когда у меня есть раздражающие данные, такие как имена с 'и &. –

1

Насколько я могу судить, документация на OPENXML не гарантирует ничего порядка. И порядок не гарантируется в реляционной таблице. Так почему бы просто не «заказать» определенный столбец, чтобы получить заказ, который вы пожелаете? Это всегда то, как вы выполняете заказы в sql.

Я не понимаю, почему вы извлекаете атрибут encryptedAccountId отдельно. Почему бы просто не вставить его в инструкцию maininsert?

Несвязанный совет, если ваша вставка транзакции генерирует личность, вы можете скопировать ее копию для вставки значений, присоединившись к этой родительской таблице на «../@id». Даже если вам не нужно ничего другого из родительской таблицы, кажется хорошей идеей, чтобы убедиться, что ни одна из ваших вложений транзакций не удалась.

пример Подсказка:

INSERT INTO 
      [TransactionValues] 
      (
       FieldID, 
       TransactionID, 
       OfficialValue, 
       FriendlyValue, 
       ParentIdentityFK --new 
      ) 
      SELECT 
       shredded.rFieldID, shredded.rTransactionID, shredded.rOfficialValue, shredded.rFriendlyValue, t.SomeIdentity 
      FROM 
       OPENXML (@Handle, '/ts/t/tv', 2)     
      WITH 
      (
       rFieldID INT '@fieldId', 
       rTransactionID UNIQUEIDENTIFIER '../@id', 
       rOfficialValue NVARCHAR (500) '@officialValue', 
       rFriendlyValue NVARCHAR (500) '@friendlyValue' 
      ) as shredded 
      join Transactions t 
       on shredded.rTransactionID = t.ID 
+0

(1) Вы предлагаете мне отправить упорядоченный параметр внутри каждого элемента, а затем запросить его заказ? Если это так, я полагаю, что я мог бы, хотя это добавляет дополнительную сложность, и я надеялся, что мне это не понадобится. В противном случае я не уверен, что получаю то, что вы предлагаете. (2) Что касается encryptedAccountId, я не видел проходящую точку в дополнительном параметре, когда он уже появляется (по другим причинам) в параметре XML. (3) Что касается значений, получающих значение Identity от родителя, это _is_ случае и не может найти способ сделать это. Я обязательно буду следить за этим предложением. – awj

+0

В sql обычно не гарантируется какой-либо заказ. Вы должны его предоставить. Вы можете «заказывать» новый атрибут, который вы добавляете, а затем анализировать в инструкции openxml. Единственная причина, по которой этот порядок поддерживается при использовании xquery вместо openxml, заключается в том, что каждый столбец, который вы разобрали, превращается в таблицу, а затем внутреннюю связанную с другими таблицами. Поэтому они должны быть в том же порядке, что и друг для друга, чтобы итоговая объединенная таблица имела тот же порядок данных, что и документ. –

 Смежные вопросы

  • Нет связанных вопросов^_^