### 13.2.8 LOAD XML 语句

[](<>)

```
LOAD XML
    [LOW_PRIORITY | CONCURRENT] [LOCAL]
    INFILE 'file_name'
    [REPLACE | IGNORE]
    INTO TABLE [db_name.]tbl_name
    [CHARACTER SET charset_name]
    [ROWS IDENTIFIED BY '<tagname>']
    [IGNORE number {LINES | ROWS}]
    [(field_name_or_user_var
        [, field_name_or_user_var] ...)]
    [SET col_name={expr | DEFAULT}
        [, col_name={expr | DEFAULT}] ...]
```

这[`加载 XML`](load-xml.html)语句将 XML 文件中的数据读入表中。这*`文件名`*必须作为文字字符串给出。这*`标签名称`*在可选的`由以下标识的行`子句也必须作为文字字符串给出，并且必须用尖括号 (`<`和`>`）。

[`加载 XML`](load-xml.html)作为运行的补充[**mysql**](mysql.html)XML 输出模式下的客户端（即，使用[`--xml`](mysql-command-options.html#option_mysql_xml)选项）。要将表中的数据写入 XML 文件，您可以调用[**mysql**](mysql.html)客户与[`--xml`](mysql-command-options.html#option_mysql_xml)和[`-e`](mysql-command-options.html#option_mysql_execute)来自系统 shell 的选项，如下所示：

```
$> mysql --xml -e 'SELECT * FROM mydb.mytable' > file.xml
```

要将文件读回表中，请使用[`加载 XML`](load-xml.html).默认情况下，`<行>`element 被认为相当于一个数据库表行；这可以使用`由以下标识的行`条款。

该语句支持三种不同的 XML 格式：

-   列名作为属性，列值作为属性值：

    ```
    <row column1="value1" column2="value2" .../>
    ```

-   列名作为标签，列值作为这些标签的内容：

    ```
    <row>
      <column1>value1</column1>
      <column2>value2</column2>
    </row>
    ```

-   列名是`姓名`的属性`<字段>`标签，值是这些标签的内容：

    ```
    <row>
      <field name='column1'>value1</field>
      <field name='column2'>value2</field>
    </row>
    ```

    这是其他 MySQL 工具使用的格式，例如[**mysql转储**](mysqldump.html).

    这三种格式都可以在同一个 XML 文件中使用；导入例程会自动检测每一行的格式并正确解释它。标签根据标签或属性名称和列名进行匹配。

    在 MySQL 8.0.21 之前，`加载 XML`不支持`数据中心`源 XML 中的部分。（错误 #30753708、错误 #98199）

    以下条款的工作方式基本相同[`加载 XML`](load-xml.html)正如他们所做的那样[`加载数据`](load-data.html)：

-   `低优先级`要么`同时`

-   `当地的`

-   `代替`要么`忽视`

-   `字符集`

-   `放`

    看[第 13.2.7 节，“加载数据语句”](load-data.html), 有关这些条款的更多信息。

`(*`field_name_or_user_var`*, ...)`是一个或多个逗号分隔的 XML 字段或用户变量的列表。用于此目的的用户变量的名称必须与 XML 文件中的字段名称匹配，前缀为`@`.您可以使用字段名称来仅选择所需的字段。可以使用用户变量来存储相应的字段值以供后续重用。

这`忽视 *`数字`* 线`要么`忽视 *`数字`* 行`子句导致第一个*`数字`*XML 文件中要跳过的行。它类似于[`加载数据`](load-data.html)声明的`忽略...行`条款。

假设我们有一个名为`人`，创建如下所示：

```
USE test;

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

进一步假设该表最初是空的。

现在假设我们有一个简单的 XML 文件`人.xml`，其内容如下所示：

```
<list>
  <person person_id="1" fname="Kapek" lname="Sainnouine"/>
  <person person_id="2" fname="Sajon" lname="Rondela"/>
  <person person_id="3"><fname>Likame</fname><lname>Örrtmons</lname></person>
  <person person_id="4"><fname>Slar</fname><lname>Manlanth</lname></person>
  <person><field name="person_id">5</field><field name="fname">Stoma</field>
    <field name="lname">Milu</field></person>
  <person><field name="person_id">6</field><field name="fname">Nirtam</field>
    <field name="lname">Sklöd</field></person>
  <person person_id="7"><fname>Sungam</fname><lname>Dulbåd</lname></person>
  <person person_id="8" fname="Sraref" lname="Encmelt"/>
</list>
```

前面讨论的每种允许的 XML 格式都在此示例文件中表示。

将数据导入到`人.xml`进入`人`表，你可以使用这个语句：

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

Query OK, 8 rows affected (0.00 sec)
Records: 8  Deleted: 0  Skipped: 0  Warnings: 0
```

在这里，我们假设`人.xml`位于 MySQL 数据目录中。如果找不到该文件，则会导致以下错误：

```
ERROR 2 (HY000): File '/person.xml' not found (Errcode: 2)
```

这`由“<person>”标识的行`子句意味着每个`<人>`XML 文件中的元素被认为等同于要导入数据的表中的一行。在这种情况下，这是`人`表中的`测试`数据库。

从服务器的响应可以看出，8 行被导入到`测试人`桌子。这可以通过一个简单的验证[`选择`](select.html)陈述：

```
mysql> SELECT * FROM person;
+-----------+--------+------------+---------------------+
| person_id | fname  | lname      | created             |
+-----------+--------+------------+---------------------+
|         1 | Kapek  | Sainnouine | 2007-07-13 16:18:47 |
|         2 | Sajon  | Rondela    | 2007-07-13 16:18:47 |
|         3 | Likame | Örrtmons   | 2007-07-13 16:18:47 |
|         4 | Slar   | Manlanth   | 2007-07-13 16:18:47 |
|         5 | Stoma  | Nilu       | 2007-07-13 16:18:47 |
|         6 | Nirtam | Sklöd      | 2007-07-13 16:18:47 |
|         7 | Sungam | Dulbåd     | 2007-07-13 16:18:47 |
|         8 | Sreraf | Encmelt    | 2007-07-13 16:18:47 |
+-----------+--------+------------+---------------------+
8 rows in set (0.00 sec)
```

如本节前面所述，这表明 3 种允许的 XML 格式中的任何一种或全部都可能出现在单个文件中，并且可以使用[`加载 XML`](load-xml.html).

刚刚显示的导入操作的逆操作——即将 MySQL 表数据转储到 XML 文件中——可以使用[**mysql**](mysql.html)来自系统 shell 的客户端，如下所示：

```
$> mysql --xml -e "SELECT * FROM test.person" > person-dump.xml
$> cat person-dump.xml
<?xml version="1.0"?>

<resultset statement="SELECT * FROM test.person" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <row>
	<field name="person_id">1</field>
	<field name="fname">Kapek</field>
	<field name="lname">Sainnouine</field>
  </row>

  <row>
	<field name="person_id">2</field>
	<field name="fname">Sajon</field>
	<field name="lname">Rondela</field>
  </row>

  <row>
	<field name="person_id">3</field>
	<field name="fname">Likema</field>
	<field name="lname">Örrtmons</field>
  </row>

  <row>
	<field name="person_id">4</field>
	<field name="fname">Slar</field>
	<field name="lname">Manlanth</field>
  </row>

  <row>
	<field name="person_id">5</field>
	<field name="fname">Stoma</field>
	<field name="lname">Nilu</field>
  </row>

  <row>
	<field name="person_id">6</field>
	<field name="fname">Nirtam</field>
	<field name="lname">Sklöd</field>
  </row>

  <row>
	<field name="person_id">7</field>
	<field name="fname">Sungam</field>
	<field name="lname">Dulbåd</field>
  </row>

  <row>
	<field name="person_id">8</field>
	<field name="fname">Sreraf</field>
	<field name="lname">Encmelt</field>
  </row>
</resultset>
```

笔记

这[`--xml`](mysql-command-options.html#option_mysql_xml)选项导致[**mysql**](mysql.html)客户端对其输出使用 XML 格式；这[`-e`](mysql-command-options.html#option_mysql_execute)选项使客户端立即执行该选项之后的 SQL 语句。看[第 4.5.1 节，“mysql - MySQL 命令行客户端”](mysql.html).

您可以通过创建一个副本来验证转储是否有效`人`表并将转储文件导入新表，如下所示：

```
mysql> USE test;
mysql> CREATE TABLE person2 LIKE person;
Query OK, 0 rows affected (0.00 sec)

mysql> LOAD XML LOCAL INFILE 'person-dump.xml'
    ->   INTO TABLE person2;
Query OK, 8 rows affected (0.01 sec)
Records: 8  Deleted: 0  Skipped: 0  Warnings: 0

mysql> SELECT * FROM person2;
+-----------+--------+------------+---------------------+
| person_id | fname  | lname      | created             |
+-----------+--------+------------+---------------------+
|         1 | Kapek  | Sainnouine | 2007-07-13 16:18:47 |
|         2 | Sajon  | Rondela    | 2007-07-13 16:18:47 |
|         3 | Likema | Örrtmons   | 2007-07-13 16:18:47 |
|         4 | Slar   | Manlanth   | 2007-07-13 16:18:47 |
|         5 | Stoma  | Nilu       | 2007-07-13 16:18:47 |
|         6 | Nirtam | Sklöd      | 2007-07-13 16:18:47 |
|         7 | Sungam | Dulbåd     | 2007-07-13 16:18:47 |
|         8 | Sreraf | Encmelt    | 2007-07-13 16:18:47 |
+-----------+--------+------------+---------------------+
8 rows in set (0.00 sec)
```

不要求 XML 文件中的每个字段都与相应表中的列匹配。跳过没有对应列的字段。您可以通过首先清空`人2`表和删除`创建`列，然后使用相同的[`加载 XML`](load-xml.html)我们之前使用的语句，如下所示：

```
mysql> TRUNCATE person2;
Query OK, 8 rows affected (0.26 sec)

mysql> ALTER TABLE person2 DROP COLUMN created;
Query OK, 0 rows affected (0.52 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> SHOW CREATE TABLE person2\G
*************************** 1. row ***************************
       Table: person2
Create Table: CREATE TABLE `person2` (
  `person_id` int(11) NOT NULL,
  `fname` varchar(40) DEFAULT NULL,
  `lname` varchar(40) DEFAULT NULL,
  PRIMARY KEY (`person_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

mysql> LOAD XML LOCAL INFILE 'person-dump.xml'
    ->   INTO TABLE person2;
Query OK, 8 rows affected (0.01 sec)
Records: 8  Deleted: 0  Skipped: 0  Warnings: 0

mysql> SELECT * FROM person2;
+-----------+--------+------------+
| person_id | fname  | lname      |
+-----------+--------+------------+
|         1 | Kapek  | Sainnouine |
|         2 | Sajon  | Rondela    |
|         3 | Likema | Örrtmons   |
|         4 | Slar   | Manlanth   |
|         5 | Stoma  | Nilu       |
|         6 | Nirtam | Sklöd      |
|         7 | Sungam | Dulbåd     |
|         8 | Sreraf | Encmelt    |
+-----------+--------+------------+
8 rows in set (0.00 sec)
```

在 XML 文件的每一行中给定字段的顺序不影响[`加载 XML`](load-xml.html);字段顺序可以因行而异，并且不需要与表中相应列的顺序相同。

如前所述，您可以使用`(*`field_name_or_user_var`*, ...)`一个或多个 XML 字段的列表（仅用于选择所需的字段）或用户变量（用于存储相应的字段值以供以后使用）。当您要将 XML 文件中的数据插入到名称与 XML 字段的名称不匹配的表列中时，用户变量会特别有用。要了解它是如何工作的，我们首先创建一个名为`个人`其结构与`人`表，但其列的名称不同：

```
mysql> CREATE TABLE individual (
    ->     individual_id INT NOT NULL PRIMARY KEY,
    ->     name1 VARCHAR(40) NULL,
    ->     name2 VARCHAR(40) NULL,
    ->     made TIMESTAMP
    -> );
Query OK, 0 rows affected (0.42 sec)
```

在这种情况下，您不能简单地将 XML 文件直接加载到表中，因为字段名和列名不匹配：

```
mysql> LOAD XML INFILE '../bin/person-dump.xml' INTO TABLE test.individual;
ERROR 1263 (22004): Column set to default value; NULL supplied to NOT NULL column 'individual_id' at row 1
```

发生这种情况是因为 MySQL 服务器查找与目标表的列名匹配的字段名。您可以通过将字段值选择到用户变量中来解决此问题，然后使用以下方法将目标表的列设置为等于这些变量的值`放`.您可以在一条语句中执行这两项操作，如下所示：

```
mysql> LOAD XML INFILE '../bin/person-dump.xml'
    ->     INTO TABLE test.individual (@person_id, @fname, @lname, @created)
    ->     SET individual_id=@person_id, name1=@fname, name2=@lname, made=@created;
Query OK, 8 rows affected (0.05 sec)
Records: 8  Deleted: 0  Skipped: 0  Warnings: 0

mysql> SELECT * FROM individual;
+---------------+--------+------------+---------------------+
| individual_id | name1  | name2      | made                |
+---------------+--------+------------+---------------------+
|             1 | Kapek  | Sainnouine | 2007-07-13 16:18:47 |
|             2 | Sajon  | Rondela    | 2007-07-13 16:18:47 |
|             3 | Likema | Örrtmons   | 2007-07-13 16:18:47 |
|             4 | Slar   | Manlanth   | 2007-07-13 16:18:47 |
|             5 | Stoma  | Nilu       | 2007-07-13 16:18:47 |
|             6 | Nirtam | Sklöd      | 2007-07-13 16:18:47 |
|             7 | Sungam | Dulbåd     | 2007-07-13 16:18:47 |
|             8 | Srraf  | Encmelt    | 2007-07-13 16:18:47 |
+---------------+--------+------------+---------------------+
8 rows in set (0.00 sec)
```

用户变量的名称*必须*匹配 XML 文件中相应字段的字段，并添加必需的`@`前缀表示它们是变量。用户变量不需要按照与相应字段相同的顺序列出或分配。

用一个`由 '<* 标识的行`标签名称`*>'`子句，可以将同一 XML 文件中的数据导入具有不同定义的数据库表中。对于此示例，假设您有一个名为`地址.xml`其中包含以下 XML：

```
<?xml version="1.0"?>

<list>
  <person person_id="1">
    <fname>Robert</fname>
    <lname>Jones</lname>
    <address address_id="1" street="Mill Creek Road" zip="45365" city="Sidney"/>
    <address address_id="2" street="Main Street" zip="28681" city="Taylorsville"/>
  </person>

  <person person_id="2">
    <fname>Mary</fname>
    <lname>Smith</lname>
    <address address_id="3" street="River Road" zip="80239" city="Denver"/>
    <!-- <address address_id="4" street="North Street" zip="37920" city="Knoxville"/> -->
  </person>

</list>
```

您可以再次使用`测试人`在本节前面定义的表中，从表中清除所有现有记录，然后显示其结构，如下所示：

```
mysql< TRUNCATE person;
Query OK, 0 rows affected (0.04 sec)

mysql< SHOW CREATE TABLE person\G
*************************** 1. row ***************************
       Table: person
Create Table: CREATE TABLE `person` (
  `person_id` int(11) NOT NULL,
  `fname` varchar(40) DEFAULT NULL,
  `lname` varchar(40) DEFAULT NULL,
  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`person_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)
```

现在创建一个`地址`表中的`测试`使用以下数据库[`创建表`](create-table.html)陈述：

```
CREATE TABLE address (
    address_id INT NOT NULL PRIMARY KEY,
    person_id INT NULL,
    street VARCHAR(40) NULL,
    zip INT NULL,
    city VARCHAR(40) NULL,
    created TIMESTAMP
);
```

要将 XML 文件中的数据导入到`人`表，执行以下[`加载 XML`](load-xml.html)语句，它指定行将由`<人>`元素，如此处所示；

```
mysql> LOAD XML LOCAL INFILE 'address.xml'
    ->   INTO TABLE person
    ->   ROWS IDENTIFIED BY '<person>';
Query OK, 2 rows affected (0.00 sec)
Records: 2  Deleted: 0  Skipped: 0  Warnings: 0
```

您可以使用[`选择`](select.html)陈述：

```
mysql> SELECT * FROM person;
+-----------+--------+-------+---------------------+
| person_id | fname  | lname | created             |
+-----------+--------+-------+---------------------+
|         1 | Robert | Jones | 2007-07-24 17:37:06 |
|         2 | Mary   | Smith | 2007-07-24 17:37:06 |
+-----------+--------+-------+---------------------+
2 rows in set (0.00 sec)
```

由于`<地址>`XML 文件中的元素在`人`表，它们被跳过。

从导入数据`<地址>`元素进入`地址`表，使用[`加载 XML`](load-xml.html)此处显示的声明：

```
mysql> LOAD XML LOCAL INFILE 'address.xml'
    ->   INTO TABLE address
    ->   ROWS IDENTIFIED BY '<address>';
Query OK, 3 rows affected (0.00 sec)
Records: 3  Deleted: 0  Skipped: 0  Warnings: 0
```

您可以看到数据是使用[`选择`](select.html)像这样的声明：

```
mysql> SELECT * FROM address;
+------------+-----------+-----------------+-------+--------------+---------------------+
| address_id | person_id | street          | zip   | city         | created             |
+------------+-----------+-----------------+-------+--------------+---------------------+
|          1 |         1 | Mill Creek Road | 45365 | Sidney       | 2007-07-24 17:37:37 |
|          2 |         1 | Main Street     | 28681 | Taylorsville | 2007-07-24 17:37:37 |
|          3 |         2 | River Road      | 80239 | Denver       | 2007-07-24 17:37:37 |
+------------+-----------+-----------------+-------+--------------+---------------------+
3 rows in set (0.00 sec)
```

数据来自`<地址>`包含在 XML 注释中的元素不会被导入。然而，由于有一个`person_id`列中的`地址`表中的值`person_id`来自父级的属性`<人>`每个元素`<地址>` *是*导入到`地址`桌子。

**安全注意事项。**与[`加载数据`](load-data.html)语句，XML 文件从客户端主机到服务器主机的传输是由 MySQL 服务器发起的。理论上，可以构建一个打补丁的服务器，它会告诉客户端程序传输服务器选择的文件，而不是客户端指定的文件。[`加载 XML`](load-xml.html)陈述。这样的服务器可以访问客户端用户具有读取访问权限的客户端主机上的任何文件。

在 Web 环境中，客户端通常从 Web 服务器连接到 MySQL。可以对 MySQL 服务器运行任何命令的用户可以使用[`本地加载 XML`](load-xml.html)读取 Web 服务器进程具有读取权限的任何文件。在这种环境中，相对于 MySQL 服务器的客户端实际上是 Web 服务器，而不是连接到 Web 服务器的用户正在运行的远程程序。

您可以通过启动服务器来禁用从客户端加载 XML 文件[`--local-infile=0`](server-system-variables.html#sysvar_local_infile)要么[`--local-infile=OFF`](server-system-variables.html#sysvar_local_infile).启动时也可以使用此选项[**mysql**](mysql.html)客户端禁用[`加载 XML`](load-xml.html)在客户端会话期间。

要防止客户端从服务器加载 XML 文件，请不要授予[`文件`](privileges-provided.html#priv_file)授予相应 MySQL 用户帐户的权限，或者如果客户端用户帐户已经拥有该权限，则撤销此权限。

重要的

撤销[`文件`](privileges-provided.html#priv_file)特权（或一开始不授予）使用户只能执行[`加载 XML`](load-xml.html)声明（以及[`加载文件（）`](string-functions.html#function_load-file)功能;它确实*不是*阻止用户执行[`本地加载 XML`](load-xml.html).要禁止此语句，您必须使用以下命令启动服务器或客户端`--local-infile=OFF`.

换句话说，[`文件`](privileges-provided.html#priv_file)权限只影响客户端是否可以读取服务器上的文件；它与客户端是否可以读取本地文件系统上的文件无关。
