LOAD DATA INFILE语法

13.2.5. LOAD DATA INFILE语法

LOAD DATA [LOW_PRIORITY | CONCURRENT] [LOCAL] INFILE 'file_name

.txt'
    [REPLACE | IGNORE]
    INTO TABLE tbl_name


    [FIELDS
        [TERMINATED BY 'string

']
        [[OPTIONALLY] ENCLOSED BY 'char

']
        [ESCAPED BY 'char

' ]
    ]
    [LINES
        [STARTING BY 'string

']
        [TERMINATED BY 'string

']
    ]
    [IGNORE number

 LINES]
    [(col_name_or_user_var

,...)]
    [SET col_name

 = expr

,...)]

LOAD DATA INFILE 语句用于高速地从一个文本文件中读取行,并装入一个表中。文件名称必须为一个文字字符串。

要了解有关INSERTLOAD DATA INFILE 的效率的对比和有关LOAD DATA INFILE 加速的更多信息,请参见7.2.16节,“INSERT语句的速度”

character_set_database 系统变量指示的字符集被用于解释文件中的信息。SET NAMEScharacter_set_client 的设置不会影响对输入的解释。

注意,目前不能载入UCS2 数据文件。

您也可以通过使用mysqlimport 应用程序载入数据文件;通过向服务器发送一个LOAD DATA INFILE 语句实现此功能。--local 选项用于使mysqlimport 从客户主机中读取数据文件。如果客户端和服务器支持压缩协议,则您可以指定—compress 选项提高在慢速网络中的性能。请参见8.10节,“mysqlimport:数据导入程序

如果您使用LOW_PRIORITY ,则LOAD DATA 语句的执行被延迟,直到没有其它的客户端从表中读取为止。

如果一个MyISAM 表满足同时插入的条件(即该表在中间有空闲块),并且您对这个MyISAM 表指定了CONCURRENT ,则当LOAD DATA 正在执行时,其它线程会从表中重新获取数据。即使没有其它线程在同时使用本表格,使用本选项也会略微影响LOAD DATA 的性能。

如果指定了LOCAL ,则被认为与连接的客户端有关:

·         如果指定了LOCAL ,则文件会被客户主机上的客户端读取,并被发送到服务器。文件会被给予一个完整的路径名称,以指定确切的位置。如果给定的是一个相对的路径名称,则此名称会被理解为相对于启动客户端时所在的目录。

·         如果LOCAL 没有被指定,则文件必须位于服务器主机上,并且被服务器直接读取。

当在服务器主机上为文件定位时,服务器使用以下规则:

·         如果给定了一个绝对的路径名称,则服务器使用此路径名称。

·         如果给定了带有一个或多个引导组件的相对路径名称,则服务器会搜索相对于服务器数据目录的文件。

·         如果给定了一个不带引导组件的文件名称,则服务器会在默认数据库的数据库目录中寻找文件。

注意,这些规则意味着名为./myfile.txt 的文件会从服务器数据目录中被读取,而名为myfile.txt 的同样的文件会从默认数据库的数据库目录中读取。例如,下面的LOAD DATA 语句会从db1 数据库目录中读取文件data.txt ,因为db1 是当前数据库。即使语句明确把文件载入到db2 数据库中的表里,也会从db1 目录中读取。

mysql> USE db1;


mysql> LOAD DATA INFILE 'data.txt' INTO TABLE db2.my_table;


注意,使用正斜杠指定Windows 路径名称,而不是使用反斜杠。如果您使用反斜杠,您必须使用两个。

出于安全原因,当读取位于服务器中的文本文件时,文件必须位于数据库目录中,或者是全体可读的。另外,要对服务器文件使用LOAD DATA INFILE ,您必须拥有FILE 权限。

5.7.3节,“MySQL提供的权限”

与让服务器直接读取文件相比,使用LOCAL 速度略慢,这是因为文件的内容必须通过客户端发送到服务器上。不过,您不需要FILE 权限来载入本地文件。

只有当您的服务器和您的客户端都许可时,LOCAL 才可运行。例如,如果使用—local-infile=0 启动mysqld ,则LOCAL 不运行。请参见5.6.4节,“LOAD DATA LOCAL安全问题”

如果您需要LOAD DATA 来从一个管道中读取,您可以使用以下方法(此处我们把/ 目录清单载入一个表格):

mkfifo /mysql/db/x/x
chmod 666 /mysql/db/x/x
find / -ls > /mysql/db/x/x
mysql -e "LOAD DATA INFILE 'x' INTO TABLE x" x

有些输入记录把原有的记录复制到唯一关键字值上。REPLACEIGNORE 关键字用于控制这些输入记录的操作。

如果您指定了REPLACE ,则输入行会替换原有行(换句话说,与原有行一样,对一个主索引或唯一索引具有相同值的行)。请参见13.2.6节,“REPLACE语法”

如果您指定IGNORE ,则把原有行复制到唯一关键字值的输入行被跳过。如果您这两个选项都不指定,则运行情况根据LOCAL 关键词是否被指定而定。不使用LOCAL 时,当出现重复关键字值时,会发生错误,并且剩下的文本文件被忽略。使用LOCAL 时,默认的运行情况和IGNORE 被指定时的情况相同;这是因为在运行中间,服务器没有办法中止文件的传输。

如果您希望在载入运行过程中忽略外键的限制,您可以在执行LOAD DATA 前发送一个SET FOREIGN_KEY_CHECKS=0 语句。

如果您对一个空的MyISAM 表使用LOAD DATA INFILE ,则所有的非唯一索引会被创建在一个独立批中(对于REPAIR TABLE )。当您有许多索引时,这通常会使LOAD DATA INFILE 大大加快。通常,LOAD DATA INFILE 的速度会非常快,但是在某些极端情况下,您可以在把文件载入到表中之前使用ALTER TABLE...DISABLE KEYS 关闭LOAD DATA INFILE ,或者在载入文件之后使用ALTER TABLE...ENABLE KEYS 再次创建索引,使创建索引的速度更快。请参见7.2.16节,“INSERT语句的速度”

LOAD DATA INFILESELECT...INTO OUTFILE 的补语。(见13.2.7节,“SELECT语法” 。)要从一个表中把数据写入一个文件中,应使用SELECT...INTO OUTFILE 。要读取文件,放回到表中,应使用LOAD DATA INFILEFIELDSLINES 子句的语法对于两个语句是一样的。两个子句都是自选的,但是如果两个都被指定了,FIELDS 必须位于LINES 的前面。

如果您指定了一个FIELDS 子句,则每个亚子句(TERMINATED BY, [OPTIONALLY] ENCLOSED BYESCAPED BY )也是自选的。不过,您必须指定其中至少一个。

如果您不指定FIELDS 子句,则默认值为假设您写下如下语句时的值:

FIELDS TERMINATED BY '\t' ENCLOSED BY '' ESCAPED BY '\\'

如果您不指定LINES 子句,则默认值为假设您写下如下语句时的值:

LINES TERMINATED BY '\n' STARTING BY ''

换句话说,当读取输入值时,默认值会使LOAD DATA INFILE 按如下方式运行:

·         在新行处寻找行的边界。

·         不会跳过任何行前缀。

·         在制表符处把行分解为字段。

·         不希望字段被包含在任何引号字符之中。

·         出现制表符、新行、或在‘\ ’前有‘\ ’时,理解为作为字段值一部分的文字字符。

相反的,当编写输出值时,默认值会使SELECT...INTO OUTFILE 按如下方式运行:

·         在字段之间写入制表符。

·         不把字段包含在任何引号字符中。

·         当字段值中出现制表符、新行或‘\ ’时,使用‘\ ’进行转义。

·         在行的末端写入新行。

注意,要写入FIELDS ESCAPED BY \\ ’,您必须为待读取的值指定两个反斜杠,作为一个单反斜杠使用。

注释:如果您已经在Windows 系统中生成了文本文件,您可能必须使用LINES TERMINATED BY \r\n ’来正确地读取文件,因为Windows 程序通常使用两个字符作为一个行终止符。部分程序,比如WordPad ,当编写文件时,可能会使用\r 作为行终止符。要读取这样的文件,应使用LINES TERMINATED BY \r ’。

如果所有您希望读入的行都含有一个您希望忽略的共用前缀,则您可以使用'prefix_string ' 来跳过前缀(和前缀前的字符)。如果某行不包括前缀,则整个行被跳过。注释:prefix_string 会出现在一行的中间。

示例:

mysql> LOAD DATA INFILE '/tmp/test.txt'


    -> INTO TABLE test LINES STARTING BY "xxx";


使用此语句,您可以读入包含有如下内容的文件:

xxx"row",1
something xxx"row",2

并只得到数据("row",1)("row",2)

IGNORE number LINES 选项可以被用于在文件的开始处忽略行。例如,您可以使用IGNORE 1 LINES 来跳过一个包含列名称的起始标题行:

mysql> LOAD DATA INFILE '/tmp/test.txt'


    -> INTO TABLE test IGNORE 1 LINES;


当您联合使用SELECT...INTO OUTFILELOAD DATA INFILE 来从一个数据库中把数据写入一个文件中,然后再读取文件,返回到数据库中时,用于两个语句的field-line-handling 选项必须匹配。否则,LOAD DATA INFILE 不会正确地理解文件的内容。假设您使用SELECT...INTO OUTFILE 来编写一个的文件,字段由逗号分隔:

mysql> SELECT * INTO OUTFILE 'data.txt'


    ->          FIELDS TERMINATED BY ','


    ->          FROM table2;


要读取由逗号分隔的文件并返回,则正确的语句应该是:

mysql> LOAD DATA INFILE 'data.txt' INTO TABLE table2


    ->           FIELDS TERMINATED BY ',';


如果您尝试使用以下所示的语句读入文件,则不会运行,因为该语句命令LOAD DATA INFILE 寻找位于字段之间的制表符:

mysql> LOAD DATA INFILE 'data.txt' INTO TABLE table2


    ->           FIELDS TERMINATED BY '\t';


结果很可能是,每个输入行被理解为一个单一字段。

LOAD DATA INFILE 也可以被用于读取从外源中获取的文件。例如,一个dBASE 格式的文件具有以逗号分隔并且包含在双引号中的字段。如果文件中的各行以新行为结尾,则此处所示的语句描述了您可以用于载入文件的field-line-handling 选项:

mysql> LOAD DATA INFILE 'data.txt' INTO TABLE tbl_name



    ->           FIELDS TERMINATED BY ',' ENCLOSED BY '"'


    ->           LINES TERMINATED BY '\n';


所有field-line-handling 选项都可以指定一个空字符串('' ) 。如果字符串不是空的,则FIELDS [OPTIONALLY] ENCLOSED BYFIELDS ESCAPED BY 值必须为单一字符。FIELDS TERMINATED BY, LINES STARTING BYLINES TERMINATED BY 值可以超过一个字符。例如,要编写由回车/ 换行成对字符作为结尾的行,或读取包含这类行的文件,则应指定一个LINES TERMINATED BY \r\n ’子句。

如果jokes 被由%% 组成的行分隔,要读取包含jokes 的文件,您可以这么操作:

mysql> CREATE TABLE jokes


    ->     (a INT NOT NULL AUTO_INCREMENT PRIMARY KEY,


    ->     joke TEXT NOT NULL);


mysql> LOAD DATA INFILE '/tmp/jokes.txt' INTO TABLE jokes


    ->     FIELDS TERMINATED BY ''


    ->     LINES TERMINATED BY '\n%%\n' (joke);


FIELDS [OPTIONALLY] ENCLOSED BY 用于控制字段的引号。对于(SELECT...INTO OUTFILE ),如果您忽略了词语OPTIONALLY ,则所有的字段都被包含在ENCLOSED BY 字符串中。此处展示了此类输出的一个示例(使用逗号作为字段分隔符):

"1","a string","100.20"
"2","a string containing a , comma","102.20"
"3","a string containing a \" quote","102.20"
"4","a string containing a \", quote and comma","102.20"

如果您指定了OPTINALLY ,则ENCLOSED BY 字符只被用于包含具有字符串数据类型(比如CHAR, BINARY, TEXTENUM )的列中的值:

1,"a string",100.20
2,"a string containing a , comma",102.20
3,"a string containing a \" quote",102.20
4,"a string containing a \", quote and comma",102.20

注意,如果在字段值内出现ENCLOSED BY 字符,则通过使用ESCAPED BY 字符作为前缀,对ENCLOSED BY 字符进行转义。另外,要注意,如果您指定了一个空的ESCAPED BY 值,则可能会生成不能被LOAD DATA INFILE 正确读取的输出值。例如,如果转义符为空字符,则刚显示的先前输出值应显示如下。请观察,第四行中的第二个字段在引号后面包含一个逗号,该引号(错误地)显示出来,作为字段的结尾:

1,"a string",100.20
2,"a string containing a , comma",102.20
3,"a string containing a " quote",102.20
4,"a string containing a ", quote and comma",102.20

对于输入值,ENCLOSED BY 字符被从字段字的末尾剥离。(不论OPTIONALLY 是否被指定都会剥离;OPTIONALLY 对输入值的解释没有影响。)如果ENCLOSED BY 字符前面带有ESCAPED BY 字符,则被理解为当前字段值的一部分。

如果字段以ENCLOSED BY 字符为开始,当出现这类字符时,只有后面接着字段或行TERMINATED BY 序列时,这类字符被认为是一个字段值的结尾。为了避免意思不明确,当在一个字段值中出现ENCLOSED BY 字符时,此字符可以重复书写,并被理解为单一的字符。例如,如果指定了ENCLOSED BY '"' ,则按照以下方法操作引号:

"The ""BIG"" boss"  -> The "BIG" boss
The "BIG" boss      -> The "BIG" boss
The ""BIG"" boss    -> The ""BIG"" boss

FIELDS ESCAPED BY 用于控制如何写入或读取特殊字符。如果FIELDS ESCAPED BY 字符不是空字符,则可以在输出中用于对以下字符加前缀:

·         FIELDS ESCAPED BY 字符

·         FIELDS [OPTIONALLY] ENCLOSED BY 字符

·         FIELDS TERMINATED BYLINES TERMINATED BY 值的第一个字符

·         ASCII 0 (在转义符之后编写的字符实际上是ASCII0 ’,而不是一个值为0 的字节)

如果FIELDS ESCAPED BY 字符为空字符,则没有字符被转义,并且NULL 被作为NULL 输出,而不是\N 。去指定一个空的转义符不是一个好办法,特别是如果数据的字段值包含任何刚给定的清单中的字符时,更不能这么做。

对于输入值,如果FIELDS ESCAPED BY 字符不是空字符,则出现这种字符时会被剥离,然后以下字符被作为字段值的一部分。例外情况是,被转义的‘0 ’或‘N ’(例如,\0\N ,此时转义符为‘\ ’)。这些序列被理解为ASCII NUL (一个零值字节)和NULL 。用于NULL 处理的规则在本节的后部进行说明。

要了解有关‘\-escape 语法的更多信息,请参见9.1节,“文字值”

在特定情况下,field-line-handling 选项相互影响:

·         如果LINES TERMINATED BY 是空字符串,并且FIELDS TERMINATED BY 不是空字符串,则各行以FIELDS TERMINATED BY 作为结尾。

·         如果FIELDS TERMINATED BYFIELDS ENCLOSED BY 值均为空值('' ) ,则使用固定行(无分隔)格式。使用固定行格式时,在字段之间不使用分隔符(但是您仍然可以有行终止符)。列值使用列的显示宽度进行写入和读取。例如,如果某列被定义为INT(7) ,则使用7 字符字段写入列值。输出时,通过读取7 个字符获取列值。

LINES TERMINATED BY 仍然用于分隔行。如果某行不包含所有字段,则其余的各列被设置到默认值。如果您没有行终止符,您应该把终止符设置为'' 。在此情况下,文本文件必须包含每行的所有字段。

固定行格式也会影响NULL 值的操作,这将在以后进行介绍。注意,如果您正在使用一个多字节字符集,则固定规格格式不会运行。

根据正在使用中的FIELDSLINES 选项的不同,NULL 值的操作有所变化:

·         对于默认的FIELDSLINES 值,NULL 被作为\N 的字段值编写,用于输出;\N 字段值被作为NULL 读取,用于输入(假设ESCAPED BY 字符为‘\ ’)。

·         如果FIELDS ENCLOSED BY 不是空值,则包含以文字词语NULL 为值的字段被作为NULL 值读取。这与被FIELDS ENCLOSED BY 字符包围的词语NULL 不同。该词语被作为字符串'NULL' 读取。

·         如果FIELDS ESCAPED BY 是空值,则NULL 被作为词语NULL 写入。

·         采用固定行格式时(当FIELDS TERMINATED BYFIELDS ENCLOSED BY 均为空值时采用),NULL 被作为一个空字符串写入。注意,这会导致在被写入文件时,表中的NULL 值和空字符串均无法辨别,这是因为两者都被作为空字符串写入。如果您需要在读取文件并返回时能够分辨两者,则您不应使用固定行格式。

LOAD DATA INFILE 不支持有些情况:

·         固定规格行(FIELDS TERMINATED BYFIELDS ENCLOSED BY 均为空值)和BLOBTEXT 列。

·         如果您指定了一个分隔符,并且该分隔符与其它的前缀一样,则LOAD DATA INFILE 不能正确地理解输入值。例如,下面的FIELDS 子句会导致问题:

·                

FIELDS TERMINATED BY '"' ENCLOSED BY '"'

·         如果FIELDS ESCAPED BY 为空值,则包含FIELDS ENCLOSED BYLINES TERMINATED BY 的字段值后面再接FIELDS TERMINATED BY 值会导致LOAD DATA INFILE 过早地停止读取一个字段或行。出现这种情况的原因是LOAD DATA INFILE 不能正确地决定字段或行值在哪里结束。

以下的例子载入了persondata 表中的所有列:

mysql> LOAD DATA INFILE 'persondata.txt' INTO TABLE persondata;


默认情况下,如果在LOAD DATA INFILE 语句的末尾处没有设列清单时,则输入行预计会包含一个字段,用于表中的每个列。如果您只想载入一个表的部分列,则应指定一个列清单:

mysql> LOAD DATA INFILE 'persondata.txt'


    ->           INTO TABLE persondata (col1,col2,...);


如果输入文件中各字段的顺序与表中各列的顺序不同,您也必须指定一个列清单。否则,MySQL 不能把输入字段和表中的列匹配起来。

列清单可以包含列名称或用户变量。支持SET 子句。这使您可以把输入值赋予用户变量,然后在把结果赋予列之前,对这些值进行变换。

SET 子句中的用户变量可以采用多种方式使用。以下例子使用数据文件中的第一列,直接用于t1.column1 的值。在用户变量被用于t2.column2 值之前,把第二列赋予用户变量。该变量从属于一个分割运行。

LOAD DATA INFILE 'file.txt'
  INTO TABLE t1
  (column1, @var1)
  SET column2 = @var1/100;

SET 子句可以被用于提供不是来源于输入文件的值。以下语句把column3 设置为当前的日期和时间:

LOAD DATA INFILE 'file.txt'
  INTO TABLE t1
  (column1, column2)
  SET column3 = CURRENT_TIMESTAMP;

您也可以通过把输入值赋予一个用户变量,同时不把变量赋予表中的列,来丢弃此输入值:

LOAD DATA INFILE 'file.txt'
  INTO TABLE t1
  (column1, @dummy, column2, @dummy, column3);

/ 变量清单和SET 子句的使用受到以下限定:

·         SET 子句中的赋值应只含有位于赋值操作符的左侧的列名称。

·         您可以在SET 赋值的右侧使用子查询。如果子查询可以返回一个值,并且此值将被赋予到一个列中,则此子查询只能是标量子查询。另外,您不能使用子查询从一个正在被载入的表中选择。

·         对于于列/ 变量清单或SET 子句,被IGNORE 子句忽略的行不被处理。

·         当载入采用固定行格式的数据时,不能使用用户变量,因为用户变量没有显示宽度。

当处理一个输入行时,LOAD DATA 会依据列/ 变量清单和SET 子句,把行拆分成字段,并使用值。然后,得到的行被插入表中。如果有用于表的BEFORE INSERTAFTER INSERT 触发器,则在插入行之前和插入行之后分别启动触发器。

如果一个输入行含有过多的字段,则多余的字段被忽略,并且警告的数量增加。

如果一个输入行含有的字段过少,则输入字段缺失的表中的列被设置为默认值。默认值赋值在13.1.5节,“CREATE TABLE语法” 中进行了说明。

如果字段值缺失,则对一个空字段值会被按不同方式理解:

·         对于字符串类型,列被设置为空字符串。

·         对于数字类型,列被设置为0

·         对于日期和时间类型,列被设置为该类型相应的“zero ”。请参见11.3节,“日期和时间类型”

如果您明确地把一个空字符串赋予一个INSERTUPDATE 语句中的字符串类型、数字类型或日期或时间类型,则产生的这些值相同。

只有在两种情况下TIMESTAMP 列被设置为当前日期和时间。一种情况时当列有一个NULL 值(也就是\N )时;另一种情况是(仅对于第一个TIMESTAMP 列),当一个字段清单被指定时,TIMESTAMP 列会从字段清单中被略去。

LOAD DATA INFILE 把所有的输入值当作字符串,所以您不能按照使用INSERT 语句的方式使用ENUMSET 列的数字值。所有的ENUMSET 值必须被指定为字符串。

LOAD DATA INFILE 语句结束时,会按以下格式返回一个信息字符串:

Records: 1  Deleted: 0  Skipped: 0  Warnings: 0

如果您正在使用C API ,您可以通过调用mysql_info() 函数获取有关语句的信息。请参见25.2.3.34节,“mysql_info()”

当值通过INSERT 语句被插入时或出现相同情况时,会发生警告(见13.2.4节,“INSERT语法” )。例外情况是,当输入行中字段过多或过少时,LOAD DATA INFILE 也生成警告。这些警告并不存储;警告的数量只用于指示运行是否良好。

您可以使用SHOW WARNINGS 来得到第一批max_error_count 警告的清单,作为有关运行错误的信息。请参见13.5.4.22节,“SHOW WARNINGS语法”

猜你喜欢

转载自douglaslau.iteye.com/blog/1471643