使用不一致的列名称加载XML LOCAL INFILE

时间:2011-12-20 22:32:10

标签: mysql xml

MySQL有一个很好的陈述:LOAD XML LOCAL INFILE

例如,如果您有此表:

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

以及名为person.xml的以下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>

如何在不操作XML文件的情况下使用MySQL语句完成相同的操作?我到处搜索但找不到答案。

4 个答案:

答案 0 :(得分:10)

将忽略XML文件中与物理列名称不对应的字段。表中没有XML中相应字段的列设置为NULL。

我要做的是加载到临时表中,如@Kolink所示,但需要添加其他列。在从XML加载数据时添加SET子句。

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    |
+-----------+--------+-------------+

答案 1 :(得分:4)

以下是我可以选择的选项:

选项1:创建具有不同字段名称的临时表(如其他答案所示)。这本来是一种令人满意的方法。但是,当我尝试它时,出现了一个新问题:由于某种原因,LOAD XML语句不接受最小化格式的空元素(例如<person />)。因此,语句失败,因为我需要偶尔加载的XML文件具有该格式的空元素。

选项2:在运行LOAD XML语句之前使用XSLT转换XML文件以更改元素名称并修改空元素格式。这是不可行的,因为XML文件非常大,并且XSLT处理引擎在处理之前将整个XML加载到内存中。

选项3:完全绕过LOAD XML语句并使用SAX解析器解析XML文件,并使用JDBC和预准备语句将记录直接插入数据库。尽管原始JDBC和预处理语句通常都很有效,但事实证明这太慢了。比LOAD XML语句慢很多。

选项4:使用LOAD DATA语句而不是LOAD XML语句,并使用与该语句关联的可选子句来满足我的需要(例如,由...分隔的行等)。这可能有效,但容易出错且不稳定。

选项5:使用快速前向解析器解析文件并同时读/写XML元素,并生成一个新的XML文件,其中包含LOAD XML语句所需格式的已修改名称。

我最终使用选项5.我使用Java Streaming API for XML(StAX)来读取XML文件并生成修改后的XML文件,然后通过JDBC从Web应用程序内部运行LOAD XML LOCAL INFILE。它工作得很好,速度非常快。

答案 2 :(得分:2)

您可以使用XML文件中的列名创建临时表(尽管必须在create temporary table查询中手动完成),将XML文件加载到该表中,然后insert into person select * from tmp_table_name

答案 3 :(得分:1)

mysql表架构:organization_type(id,name)

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 id=@ItemID, name=@Name