文/freenikhtml
將外部數據導入(import)數據庫是在數據庫應用中一個很常見的需求。其實這就是在數據的管理和操做中的ETL (Extract, transform, load)的L (Load)部分,也就是說,將特定結構(structure)或者格式(format)的數據導入某個目的地(好比數據庫,這裏咱們討論MySQL)。node
本文要討論的內容,是如何方便地將多種格式(JSON, Text, XML, CSV)的數據導入MySQL之中。mysql
本文大綱:git
將Text文件(包括CSV文件)導入MySQLgithub
將XML文件導入MySQLsql
將JSON文件導入MySQL數據庫
使用MySQL workbench的Table Data Export and Import Wizard進行JSON或CSV文件的導入導出json
這裏咱們的討論是基於一個假定,Text file和CSV file是有着比較規範的格式的(properly formatted),好比說每行的每一個數據域(field)之間是由一個共同的分隔符(好比tab: \t
)分隔的。ubuntu
那麼首先,你須要根據你的數據的格式(有哪些域),來設計好數據庫的對應的表 (的Schema)。segmentfault
舉個例子,要處理的Text文件或者CSV文件是以\t
做爲分隔符的,每行有id, name, balance這麼三個數據域,那麼首先咱們須要在數據庫中建立這個表:
CREATE TABLE sometable(id INT, name VARCHAR(255), balance DECIMAL(8,4));
建立成功之後就能夠導入了。操做方式很簡單:
LOAD DATA LOCAL INFILE '你的文件路徑(如~/file.csv)' INTO TABLE sometable FIELDS TERMINATED BY '\t' [ENCLOSED BY '"'(可選)] LINES TERMINATED BY '\n' (id, name, balance)
這裏要注意的是,咱們須要開啓local-infile這個MySQL的配置參數,纔可以成功導入。究其緣由,從MySQL的Manual中能夠看到這麼一段話:
LOCAL works only if your server and your client both have been configured to permit it. For example, if mysqld was started with --local-infile=0, LOCAL does not work. See Section 6.1.6, 「Security Issues with LOAD DATA LOCAL」.
這是MySQL出於安全考慮的默認配置。所以,咱們須要在配置文件my.cnf中(以Debian發行版的Linux, 如Ubuntu爲例, 便是在/etc/my.cnf中),確保:
local-infile=1
抑或是在命令行啓動MySQL時加上--local-infile這一項:
mysql --local-infile -uroot -pyourpwd yourdbname
此外,咱們也可使用MySQL的一個官方導入程序 mysqlimport,這個程序本質上就是爲LOAD DATA FILE提供了一個命令行的interface,很容易理解,咱們這裏就再也不詳述。
這件事的完成方式,與咱們的XML的形式有着很大的關係。
舉個例子說,當你的XML數據文件有着很很是規範的格式,好比:
<?xml version="1.0"?> <row> <field name="id">1</field> <field name="name">Free</field> <field name="balance">2333.3333</field> </row> <row> <field name="id">2</field> <field name="name">Niki</field> <field name="balance">1289.2333</field> </row>
或者
<row column1="value1" column2="value2" .../>
咱們就能夠很方便使用LOAD XML
來導入,這裏能夠參見MySQL的官方手冊--LOAD XML Syntax。
然而咱們可能有另一些需求,好比說,咱們可能會想要將XML文件的域映射到不一樣名字的列(TABLE COLUMN)之中。這裏要注意,MySQL v5.0.7之後,MySQL的Stored Procedure中不能再運行LOAD XML INFILE
或者LOAD DATA INFILE
。因此轉換的程序(procedure)的編寫方式與在此以前有所不一樣。這裏,咱們須要使用 Load_File()
和ExtractValue()
這兩個函數。
如下是一個示例XML文件和程序:
文件:
<?xml version="1.0"?> <some_list> <someone id="1" fname="Rob" lname="Gravelle"/> <someone id="2" fname="Al" lname="Bundy"/> <someone id="3" fname="Little" lname="Richard"/> </some_list>
程序:
DELIMITER $$ CREATE DEFINER=`root`@`localhost` PROCEDURE `import_some_xml`(path varchar(255), node varchar(255)) BEGIN declare xml_content text; declare v_row_index int unsigned default 0; declare v_row_count int unsigned; declare v_xpath_row varchar(255); set xml_content = load_file(path); -- calculate the number of row elements. set v_row_count = extractValue(xml_content, concat('count(', node, ')')); -- loop through all the row elements while v_row_index < v_row_count do set v_row_index = v_row_index + 1; set v_xpath_row = concat(node, '[', v_row_index, ']/@*'); insert into applicants values ( extractValue(xml_content, concat(v_xpath_row, '[1]')), extractValue(xml_content, concat(v_xpath_row, '[2]')), extractValue(xml_content, concat(v_xpath_row, '[3]')) ); end while; END
在MySQL中,使用它進行導入:
call import_some_xml('你的XML文件路徑', '/some_list/someone');
程序至關的直白,只要瞭解一下MySQL的腳本編寫便可。
這裏提一下DELIMITER $$
。咱們知道MySQL的命令分隔符默認爲分號,然而腳本中很顯然是有分號的,可是咱們並不但願當即執行,因此咱們須要臨時更改分隔符。
如何將JSON文件導入MySQL中,是一個頗有趣的話題。JSON是一種如今至關經常使用的文件結構,因此掌握它的導入具備比較普遍的意義。
不少時候,咱們處理的JSON數據是以以下形式出現的:
{"name":"Julia","gender":"female"} {"name":"Alice","gender":"female"} {"name":"Bob","gender":"male"} {"name":"Julian","gender":"male"}
而並非規整的[{},{},{},{}]
(一些NoSQL數據庫的Export)。
這樣的形勢對於載入有一個好處:由於每一行是一個JSON Object,因此咱們即可以按行處理此文件,而不須要由於JSON的嚴格結構將整個文件(好比一個許多G的.json文件)所有載入。
common-schema是一個應用很普遍的MySQL的框架,它有着很豐富的功能和詳細的文檔。咱們可使用它的JSON解析的功能。(它還具備JSON轉換成XML等等方便的功能)
具體說來,將common-schema導入以後,使用它的extract_json_value
函數便可。源碼中:
create function extract_json_value( json_text text charset utf8, xpath text charset utf8 ) returns text charset utf8
該函數接受兩個參數,一個是json_text,表示json文件的內容,另外一個是xpath,表示數據的結構(這裏能夠類比XML文件的處理)。不少讀者應該知道,XPath是用來對XML中的元素進行定位的,這裏也能夠做同樣的理解。
以本段開始的幾行JSON爲例,這裏common-schema的使用以下例:
select common_schema.extract_json_value(f.event_data,'/name') as name, common_schema.extract_json_value(f.event_data,'/gender') as gender, sum(f.event_count) as event_count from json_event_fact f group by name, gender;
關於event_data,咱們須要先理解LOAD DATA INFILE是一個event,不一樣的event type對應不一樣的event data。這部分知識能夠參看Event Data for Specific Event Types
若是感興趣,能夠參看其源碼。參看一個受到普遍使用的項目的源碼,對於自身成長是頗有益的。
固然了,咱們也能夠像以前處理XML文件導入同樣,本身編寫程序。這裏便再也不給出實例程序,有興趣的讀者能夠自行編寫或者跟筆者交流。
這是Anders Karlsson的一個完成度很高的做品。這一份程序由C寫成。它依賴於一個JSON Parser,Jansson。他們都有着比較好的維護和文檔,因此使用上體驗很好。
mysqljsonimport的下載在SourceForge上。具體使用參照其文檔便可。
爲了方便不熟悉源碼安裝的朋友,筆者在這裏提一下安裝流程和注意事項。
安裝命令順序以下:
$ wget http://sourceforge.net/projects/mysqljson/files/myjsonimport_1.6/mysqljsonimport-1.6.tar.gz $ tar xvfz mysqljsonimport-1.6.tar.gz $ cd mysqljsonimport-1.6 $ ./configure –-with-mysql=/xxx/mysql $ make $ make check $ sudo make install
--with-mysql
這一步不是必要的,只要你安裝的mysql的路徑是系統的默認路徑。很關鍵的,並且很容易被不熟悉的朋友忽略的是,這一個C程序要成功編譯和運行,是須要MySQL的C API的,因此須要安裝的依賴,除了jansson,還有libmysqlclient-dev。
jansson的安裝就是簡單的源碼安裝,libmysqlclient-dev則可使用包管理工具(好比ubuntu中使用apt-get便可;編譯和安裝前,建議先sudo apt-get update
以免沒必要要的麻煩)。
導入命令:
$ ./mysqljsonimport –-database test –-table tablename jsonfilename
還有一個parser,做者是Kazuho,感興趣的讀者能夠參看一下,他的相關博文是mysql_json - a MySQL UDF for parsing JSON ,github項目是mysql_json。
Workbench這個工具對於許多不熟悉SQL語言或者命令行的朋友仍是很方便和友好的。利用它,能夠方便地導入和導出CSV和JSON文件。
具體操做圖例參見MySQL官方手冊便可:Table Data Export and Import Wizard,這裏再也不贅述。
本文介紹了將不一樣格式(JSON, Text, XML, CSV)的文件導入MySQL數據庫的一些詳細手段,並進行了一些分析,目的在於幫助讀者掃除一些導入的障礙,理清一些概念。之因此沒有討論導出,是由於導出是一個MySQL到外的操做,是以MySQL自己爲轉移的,只要參考MySQL自己的機理便可。
真正對於大量數據的導入導出,須要思考的問題會不少(好比說在導入時,如何考慮Sharding),這須要另開一篇討論了。
謝謝閱讀,歡迎指正。
做者:
freenik@Jianshu, SegmentFault;
VonRyan@CSDN
本文采用如下協議進行受權:自由轉載-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0,轉載請標明做者出處,尊重原創。