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语句完成相同的操作?我到处搜索但找不到答案。
答案 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