Имейте XML-файл, он нужен для заполнения нескольких таблиц SQL - PullRequest
1 голос
/ 03 августа 2010

У меня есть файл XML, который мне нужен для заполнения нескольких таблиц SQL, и мне было интересно, как это лучше всего сделать.Я думал, набор данных, или xslt, но я честно не уверен.Вот мой сгенерированный XML (его часть)

 <?xml version="1.0" encoding="utf-8" standalone="yes" ?> 
- <!-- Created: 8/3/2010 12:09:15 PM
  --> 
- <Trip>
- <TripDetails>
  <DepartureDate /> 
  <ReturnDate /> 
  <TripTypeA>3</TripTypeA> 
  <TripTypeB>1</TripTypeB> 
  <PurposeOfTrip>vacation</PurposeOfTrip> 
  <Region>5</Region> 
- <Countries>
  <Country>105</Country> 
  <Country>135</Country> 
  </Countries>
- <Cities>
  <City>Cancun</City> 
  <City>Tokyo</City> 
  <City>Mayo</City> 
  </Cities>
  <OverallRating>4</OverallRating> 
  <Suppliers>53</Suppliers> 
  <SuppliersComments>Good flight</SuppliersComments> 
- <Transport>
  <TransportType>1</TransportType> 
  <TransportType>3</TransportType> 
  </Transport>
  <TransportComment>Transportation was fast</TransportComment> 

У меня есть пара разных таблиц, которые мне нужно заполнить (например, сокращенно)

TripDetails (TripID, TripTypeA, TripTypeB, SupplierID, overallRating)
TripCountries (TripCountryID, TripID, CountryCode)

У меня есть еще кучатаблицы (города, транспорт), но если я смогу выяснить, как обновить TripDetails (основная таблица) и TripCountries (это таблица, объединяющая TripDetails и Страны), думаю, все будет хорошо, спасибо!

Ответы [ 3 ]

1 голос
/ 03 августа 2010

Предполагая, что вы используете SQL Server, вы должны разобрать XML в DataTable s и использовать объект SqlBulkCopy, чтобы перебросить их в базу данных очень быстро. Есть много ресурсов, которые помогут вам узнать о SqlBulkCopy. Вот недавнее обсуждение другого вопроса StackOverflow, с которого можно начать: Sql Server 2008 Настройка с большими транзакциями (700 КБ + строки / транзакция)

Если файл XML действительно большой, вам следует быть осторожным, какой тип парсера вы используете. XDocument и XmlDocument загружают все это в память. Если файлы достаточно малы, скажем, менее 10 МБ, с этими синтаксическими анализаторами у вас все будет в порядке.


EDIT:

Вот краткий макет того, как вы можете получить XML в DataTables. Он в VB, так как VB делает XML немного проще.

Option Strict On : Option Explicit On : Option Infer On : Option Compare Binary

Imports System.Data
Imports System.Linq
Imports System.Xml.Linq

Module Module1

    Sub Main()
      Dim xml =
         <Trip>
            <TripDetails id="1">
               <DepartureDate/> 
               <ReturnDate/> 
               <TripTypeA>3</TripTypeA> 
               <TripTypeB>1</TripTypeB> 
               <PurposeOfTrip>vacation</PurposeOfTrip> 
               <Region>5</Region> 
               <Countries>
                  <Country>105</Country> 
                  <Country>135</Country> 
               </Countries>
               <Cities>
                  <City>Cancun</City> 
                  <City>Tokyo</City> 
                  <City>Mayo</City> 
               </Cities>
               <OverallRating>4</OverallRating> 
               <Suppliers>53</Suppliers> 
               <SuppliersComments>Good flight</SuppliersComments> 
               <Transport>
                  <TransportType>1</TransportType> 
                  <TransportType>3</TransportType> 
               </Transport>
               <TransportComment>Transportation was fast</TransportComment>
            </TripDetails>
         </Trip>

         Dim dtTripDetails As New DataTable()
         With dtTripDetails.Columns
            .Add("TripID", GetType(Integer))
            .Add("TripTypeA", GetType(Integer))
            .Add("DepartureDate", GetType(DateTime))
            .Add("TransportComment", GetType(String))
         End With

         Dim dtTripDetailXrefCountries As New DataTable()
         With dtTripDetailXrefCountries.Columns
            .Add("TripID", GetType(Integer))
            .Add("CountryID", GetType(Integer))
         End With

         Dim xdetails = From td In xml.Descendants("TripDetails") Select td
         For Each xdetailRecord As XElement In xdetails
            Dim tripID As Integer = CInt(xdetailRecord.Attribute("id").Value)
            Dim tripTypeA As Integer = CInt(xdetailRecord.Element("TripTypeA").Value)
            Dim strDepDate As String = xdetailRecord.Element("DepartureDate").Value
            Dim depDate As Object = If(String.IsNullOrEmpty(strDepDate), CType(DBNull.Value, Object), CType(DateTime.Parse(strDepDate), Object))
            Dim transportComment As String = xdetailRecord.Element("TransportComment").Value
            dtTripDetails.Rows.Add(tripID, tripTypeA, depDate, transportComment)

            Dim xcountries = From c In xdetailRecord.Element("Countries").Elements("Country") Select c
            For Each xcountryRecord As XElement In xcountries
               Dim countryID As Integer = CInt(xcountryRecord.Value)
               dtTripDetailXrefCountries.Rows.Add(tripID, countryID)
            Next
         Next

         Console.WriteLine("Done")
         Console.ReadKey(True)

    End Sub

End Module

Кстати: при выполнении ETL такого типа лучше сначала закачать данные в промежуточные таблицы, а не прямо в рабочие таблицы. Таким образом, вы можете проверять типы данных и обеспечивать ссылочную целостность, а также обрабатывать управление ключами и располагать все идеально, без блокировки или загрязнения рабочих таблиц.

0 голосов
/ 03 августа 2010

Вам необходимо указать, какой движок базы данных вы используете.Поскольку вы указали тег Linq, я предполагаю, что вы используете сервер Microsoft SQL.

Вы можете легко передать документ в виде строки в хранимую процедуру.В этой хранимой процедуре вы определяете некоторые схемы временных таблиц и используете sp_xml_preparedocument, OPENXML (и связанные функции) для заполнения этих временных таблиц данными из документа XML.Теперь вы можете просто использовать стандартный SQL для вставки в ваши постоянные таблицы из временных таблиц, используя любые необходимые проекции, объединения или другие преобразования.Память также больше не является проблемой в большинстве случаев, поскольку все это выполняется внутри MSSQL Server.

Дополнительная информация: http://msdn.microsoft.com/en-us/library/aa260385(SQL.80).aspx http://msdn.microsoft.com/en-us/library/aa276847(SQL.80).aspx

Пример (не проверено):

declare @docHandle int
declare @xmlContent varchar(500)
set @doc ='<root><items><item value="1"/><item value="2"/></item></root>'

exec sp_xml_preparedocument @docHandle OUTPUT, @xmlContent

insert into myTable ([ItemValue])
select value from OPENXML(@docHandle, '/root/items/item')

exec sp_xml_removedocument @docHandle 

Обратите внимание, что это соглашения SQL 2000.В SQL 2005 существуют эквивалентные соглашения T-SQL, которые более удобочитаемы, чем эти предшественники хранимых процедур.Тем не менее, я считаю, что эти соглашения все еще доступны в SQL 2005 и SQL 2008.

0 голосов
/ 03 августа 2010

Вы можете довольно легко использовать возможности XQuery в SQL Server 2005, например, иметь сохраненный процесс, который принимает эти строки XML в качестве входных данных:

CREATE PROCEDURE dbo.StoreTripDetails(@XmlContent XML)
AS BEGIN
   DECLARE @NewTripID INT

   INSERT INTO dbo.TripDetails(TripTypeA, TripTypeB, SupplierID, overallRating)
       SELECT
        Trip.Details.value('(TripTypeA)[1]', 'int') 'TripTypeA',
        Trip.Details.value('(TripTypeB)[1]', 'int') 'TripTypeB',
        Trip.Details.value('(Suppliers)[1]', 'int') 'SupplierID',
        Trip.Details.value('(OverallRating)[1]', 'int') 'OverallRating'
       FROM
        @XmlContent.nodes('/Trip/TripDetails') AS Trip(Details)

    SELECT @NewTripID = SCOPE_IDENTITY()

    INSERT INTO dbo.TripCountries(TripID, CountryCode)
        SELECT
        @NewTripID, Trip.Countries.value('(.)[1]', 'int') 
        FROM
        @XmlContent.nodes('/Trip/TripDetails/Countries/Country') AS Trip(Countries)
 END

, а затем вы можете вызвать этот хранимый процесс из своего кода C #довольно легко и передать фрагмент XML, представляющий одну поездку.

...