文/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,转载请标明做者出处,尊重原创。