2011-12-20 4 views
7

MySQL имеет хороший оператор: НАГРУЗКА XML LOCAL INFILEНАГРУЗКИ XML LOCAL INFILE с противоречивыми именами столбцов

Например, если у вас есть эта таблица:

CREATE TABLE person (
    person_id INT NOT NULL PRIMARY KEY, 
    fname VARCHAR(40) NULL, 
    lname VARCHAR(40) NULL 
); 

и следующий файл XML под названием person.xml :

<list> 
     <person> 
      <person_id>1</person_id> 
      <fname>Mikael</fname> 
      <lname>Ronström</lname> 
     </person> 
     <person> 
      <person_id>2</person_id> 
      <fname>Lars</fname> 
      <lname>Thalmann</lname> 
     </person> 
</list> 

Вы можете сделать это:

LOAD XML LOCAL INFILE 'person.xml' 
INTO TABLE person 
ROWS IDENTIFIED BY '<person>'; 

Мой вопрос: что, если имена столбцов в XML-файле были разными, чем в таблице? Например:

<list> 
     <person> 
      <PersonId>1</PersonId> 
      <FirstName>Mikael</FirstName> 
      <LastName>Ronström</LastName> 
     </person> 
     <person> 
      <PersonId>2</PersonId> 
      <FirstName>Lars</FirstName> 
      <LastName>Thalmann</LastName> 
     </person> 
</list> 

Как вы можете сделать то же самое с оператором MySQL без манипуляции с XML-файлом? Я искал везде, но не мог найти ответа.

ответ

4

Ниже перечислены доступные мне варианты:

Вариант 1: Создайте временную таблицу с разными названиями полей (как это было предложено другие ответы). Это было бы удовлетворительным подходом. Однако, когда я это пробовал, возникла новая проблема: оператор LOAD XML по какой-то причине не принимает минимальные формальные элементы формы (например, <person />). Таким образом, утверждение завершилось неудачно, потому что файлы XML, которые мне нужно загрузить, иногда имеют пустые элементы в этом формате.

Вариант 2: Преобразование XML-файла с помощью XSLT перед запуском оператора LOAD XML для изменения имен элементов и изменения форматов пустых элементов. Это было невозможно, потому что XML-файлы очень большие, а процессоры обработки XSLT загружают весь XML в память перед обработкой.

Вариант 3: полностью обойти оператор LOAD XML и использовать синтаксический анализатор SAX для анализа XML-файла и вставки записей непосредственно в базу данных с использованием JDBC и подготовленных операторов. Несмотря на то, что сырые JDBC и подготовленные заявления, как правило, эффективны, это оказалось слишком медленным. MUCH медленнее, чем оператор LOAD XML.

Вариант 4: Используйте инструкцию LOAD DATA вместо инструкции LOAD XML и поиграйте с необязательными предложениями, связанными с этим оператором, в соответствии с моими потребностями (например, линии, разделенные и т. Д.). Это могло бы сработать, но было бы ошибкой и нестабильной.

Вариант 5: проанализируйте файл с помощью простого анализатора прямого чтения и чтения/записи XML-элементов одновременно и создайте новый XML-файл с измененными именами в желаемом формате для оператора LOAD XML.

В результате я использовал вариант 5. Я использовал Java Streaming API для XML (StAX) для чтения XML-файла и создания модифицированного XML-файла, а затем запуская LOAD XML LOCAL INFILE через JDBC из веб-приложения. Он отлично работает, и он очень быстрый.

2

Вы можете создать временную таблицу, используя имена столбцов из XML-файла (хотя это нужно сделать вручную в запросе create temporary table), загрузите XML-файл в эту таблицу, а затем insert into person select * from tmp_table_name.

+0

Это очень хорошо работать вокруг. Однако, поскольку я прокомментировал ответ Билла Карвина, есть еще одна проблема с оператором LOAD XML. Он не принимает минимальные пустые теги, такие как . Можете ли вы придумать решение этой проблемы? – stepanian

+0

Я никогда не работал с 'LOAD XML', поэтому я только что получил обоснованное предположение об этом ответе. Поэтому нет, к сожалению, я не знаю решения этой проблемы, кроме загрузки XML-файла на другом языке (например, PHP), анализа его, а затем отправки результирующего запроса в базу данных. –

+1

FYI Ошибка загрузки тегов была ошибкой и была исправлена: _Prior to MySQL 5.5.46, LOAD XML не обрабатывал пустые XML-элементы в форме правильно. (Ошибка № 67542, Ошибка # 16171518) _. Из [здесь] (https://dev.mysql.com/doc/refman/5.5/en/load-xml.html) – radman

10

Поля в файле XML, которые не соответствуют физическим именам столбцов, игнорируются. И столбцы в таблице, которые не имеют соответствующих полей в XML, установлены в NULL.

Что бы я сделал, это загрузить временную таблицу, как предлагает @Kolink, но с дополнительными столбцами. Добавьте предложение SET при загрузке данных из XML.

CREATE TEMP TABLE person_xml LIKE person; 

ALTER TABLE person_xml 
    ADD COLUMN FirstName VARCHAR(40), 
    ADD COLUMN LastName VARCHAR(40), 
    ADD COLUMN PersonId INT; 

LOAD XML LOCAL INFILE 'person.xml' INTO TABLE person_xml 
    SET person_id = PersonId, fname = FirstName, lname = LastName; 

SELECT * FROM person_xml; 
+-----------+--------+-------------+-----------+-------------+----------+ 
| person_id | fname | lname  | FirstName | LastName | PersonId | 
+-----------+--------+-------------+-----------+-------------+----------+ 
|   1 | Mikael | Ronström | Mikael | Ronström |  1 | 
|   2 | Lars | Thalmann | Lars  | Thalmann |  2 | 
+-----------+--------+-------------+-----------+-------------+----------+ 

Затем скопируйте в реальную таблицу, выбрав подмножество столбцов.

INSERT INTO person SELECT person_id, fname, lname FROM person_xml; 

В качестве альтернативы, отбросьте дополнительные столбцы и используйте SELECT *.

ALTER TABLE person_xml 
    DROP COLUMN PersonId, 
    DROP COLUMN FirstName, 
    DROP COLUMN LastName; 

INSERT INTO person SELECT * FROM person_xml; 

SELECT * FROM person; 

+-----------+--------+-------------+ 
| person_id | fname | lname  | 
+-----------+--------+-------------+ 
|   1 | Mikael | Ronström | 
|   2 | Lars | Thalmann | 
+-----------+--------+-------------+ 
+0

Спасибо. Возникла новая проблема. По-видимому, этому утверждению не нравятся пустые элементы в форме . Для этого требуются отдельные открытые и закрытые теги. Я не уверен, есть ли способ обойти это. – stepanian

+0

Я бы сказал, вам следует изучить XSLT. –

+0

Как XSLT поможет здесь? – stepanian

4

немного Hacky, но рабочий раствор, используя хороший старый LOAD DATA INFILE:

LOAD DATA LOCAL INFILE '/tmp/xml/loaded.xml' 
INTO TABLE person 
CHARACTER SET binary 
LINES STARTING BY '<person>' TERMINATED BY '</person>' 
(@person) 
SET 
    person_id = ExtractValue(@person:=CONVERT(@person using utf8), 'PersonId'), 
    fname = ExtractValue(@person, 'FirstName'), 
    lname = ExtractValue(@person, 'LastName') 
; 

P.S. Возможно, вам понадобится дополнительная игра с разделителем поля, если данные содержат запятые.

+0

Это может быть ошибка. Слишком взломано. Спасибо за ваш ответ. – stepanian

+0

Спасибо. Преимущество скорости над «LOAD XML» на порядок – myol

0

MySQL таблицы схемы: organization_type (номер, имя)

organizationtype.xml:

<NewDataSet> 
    <row> 
     <ItemID>1</ItemID> 
     <ItemCreatedBy>53</ItemCreatedBy> 
     <ItemCreatedWhen>2014-03-10T22:53:43.947+10:00</ItemCreatedWhen> 
     <ItemModifiedBy>53</ItemModifiedBy> 
     <ItemModifiedWhen>2014-03-10T22:53:43.99+10:00</ItemModifiedWhen> 
     <ItemOrder>1</ItemOrder> 
     <ItemGUID>e2ad051f-b7ea-4feb-b91e-f558f6f632a0</ItemGUID> 
     <Name>Company Type 1</Name> 
    </row> 

и MySQL импорта запрос будет выглядеть следующим образом:

LOAD XML INFILE '/var/lib/mysql-files/organizationtype.xml' 
INTO TABLE organization_type (@ItemID, @Name) 
SET [email protected], [email protected] 
Смежные вопросы