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 語句用於高速地從一個文本文件中讀取行,並裝入一個表中。文件名稱必須爲一個文字字符串。
要了解有關INSERT 和LOAD DATA INFILE 的效率的對比和有關LOAD DATA INFILE 加速的更多信息,請參見7.2.16節,“INSERT語句的速度” 。
由character_set_database 系統變量指示的字符集被用於解釋文件中的信息。SET NAMES 和character_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 權限。
與讓服務器直接讀取文件相比,使用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
有些輸入記錄把原有的記錄複製到唯一關鍵字值上。REPLACE 和IGNORE 關鍵字用於控制這些輸入記錄的操作。
如果您指定了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 INFILE 是SELECT...INTO OUTFILE 的補語。(見13.2.7節,“SELECT語法” 。)要從一個表中把數據寫入一個文件中,應使用SELECT...INTO OUTFILE 。要讀取文件,放回到表中,應使用LOAD DATA INFILE 。FIELDS 和LINES 子句的語法對於兩個語句是一樣的。兩個子句都是自選的,但是如果兩個都被指定了,FIELDS 必須位於LINES 的前面。
如果您指定了一個FIELDS 子句,則每個亞子句(TERMINATED BY, [OPTIONALLY] ENCLOSED BY 和ESCAPED 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 OUTFILE 和LOAD 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 BY 和FIELDS ESCAPED BY 值必須爲單一字符。FIELDS TERMINATED BY, LINES STARTING BY 和LINES 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, TEXT 或ENUM )的列中的值:
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 BY 和LINES TERMINATED BY 值的第一個字符
· ASCII 0 (在轉義符之後編寫的字符實際上是ASCII ‘0 ’,而不是一個值爲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 BY 和FIELDS ENCLOSED BY 值均爲空值('' ) ,則使用固定行(無分隔)格式。使用固定行格式時,在字段之間不使用分隔符(但是您仍然可以有行終止符)。列值使用列的顯示寬度進行寫入和讀取。例如,如果某列被定義爲INT(7) ,則使用7 字符字段寫入列值。輸出時,通過讀取7 個字符獲取列值。
LINES TERMINATED BY 仍然用於分隔行。如果某行不包含所有字段,則其餘的各列被設置到默認值。如果您沒有行終止符,您應該把終止符設置爲'' 。在此情況下,文本文件必須包含每行的所有字段。
固定行格式也會影響NULL 值的操作,這將在以後進行介紹。注意,如果您正在使用一個多字節字符集,則固定規格格式不會運行。
根據正在使用中的FIELDS 和LINES 選項的不同,NULL 值的操作有所變化:
· 對於默認的FIELDS 和LINES 值,NULL 被作爲\N 的字段值編寫,用於輸出;\N 字段值被作爲NULL 讀取,用於輸入(假設ESCAPED BY 字符爲‘\ ’)。
· 如果FIELDS ENCLOSED BY 不是空值,則包含以文字詞語NULL 爲值的字段被作爲NULL 值讀取。這與被FIELDS ENCLOSED BY 字符包圍的詞語NULL 不同。該詞語被作爲字符串'NULL' 讀取。
· 如果FIELDS ESCAPED BY 是空值,則NULL 被作爲詞語NULL 寫入。
· 採用固定行格式時(當FIELDS TERMINATED BY 和FIELDS ENCLOSED BY 均爲空值時採用),NULL 被作爲一個空字符串寫入。注意,這會導致在被寫入文件時,表中的NULL 值和空字符串均無法辨別,這是因爲兩者都被作爲空字符串寫入。如果您需要在讀取文件並返回時能夠分辨兩者,則您不應使用固定行格式。
LOAD DATA INFILE 不支持有些情況:
· 固定規格行(FIELDS TERMINATED BY 和FIELDS ENCLOSED BY 均爲空值)和BLOB 或TEXT 列。
· 如果您指定了一個分隔符,並且該分隔符與其它的前綴一樣,則LOAD DATA INFILE 不能正確地理解輸入值。例如,下面的FIELDS 子句會導致問題:
· FIELDS TERMINATED BY '"' ENCLOSED BY '"'
· 如果FIELDS ESCAPED BY 爲空值,則包含FIELDS ENCLOSED BY 或LINES 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 INSERT 或AFTER INSERT 觸發器,則在插入行之前和插入行之後分別啓動觸發器。
如果一個輸入行含有過多的字段,則多餘的字段被忽略,並且警告的數量增加。
如果一個輸入行含有的字段過少,則輸入字段缺失的表中的列被設置爲默認值。默認值賦值在13.1.5節,“CREATE TABLE語法” 中進行了說明。
如果字段值缺失,則對一個空字段值會被按不同方式理解:
· 對於字符串類型,列被設置爲空字符串。
· 對於數字類型,列被設置爲0 。
· 對於日期和時間類型,列被設置爲該類型相應的“zero ”。請參見11.3節,“日期和時間類型” 。
如果您明確地把一個空字符串賦予一個INSERT 或UPDATE 語句中的字符串類型、數字類型或日期或時間類型,則產生的這些值相同。
只有在兩種情況下TIMESTAMP 列被設置爲當前日期和時間。一種情況時當列有一個NULL 值(也就是\N )時;另一種情況是(僅對於第一個TIMESTAMP 列),當一個字段清單被指定時,TIMESTAMP 列會從字段清單中被略去。
LOAD DATA INFILE 把所有的輸入值當作字符串,所以您不能按照使用INSERT 語句的方式使用ENUM 或SET 列的數字值。所有的ENUM 和SET 值必須被指定爲字符串。
當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語法” 。