mysql cookbook00010
10.0 引言
在数据导入和导出遇到的问题?
1. 如何处理数据文件结构,当一个文件的格式不适合导入时,你需要将其转换成其他格式,
这可能包括诸如改变列分隔符,行结束序列以及在文件中去除或重新排列
2. 如何处理数据文件内容,当你不确定数据文件是否合法,你需要对其进行预处理以校验和重新格式化内容。
数字值可能需要检验以确定是否处在某个特定范围,日期是否符合ISO格式等等
概序
在最基本的形态来看,一段输入流不过是没有字节的集合罢了,但想导入mysql那么必须要知道以下几点知识
1. 记录分隔符是什么? 知道这个可以让你将输入流分隔成记录。
2. 域定界符是什么? 知道这个可以让你知道怎样将记录再分隔成域值。识别数据值的过程一般是剥离数据值周围的引号,以及在数据值内部的换码序列
将输入分解成记录和域是从输入中抽取数据值的关键,但是这完成后,还是可能处于不能被直接使用的形式,还需要考虑一下问题
1. 列的顺序和数目是否同数据中表的结构相匹配,不匹配需要对表的列进行排序或丢弃
2. 数据值是否要进行重新的验证或者格式化
3. NULL或空值该如何处理,他们被允许吗? NULL值能否被检测出
文件格式
1. 制表定界符
数据值存放在文件的多行中,使用制表符来分隔每个值:a b c
2. 逗号定界符(csv)
用逗号把存放在行内的数据值分隔开来,然而内部本身也存在逗号或空格 这时需要用引号来分隔:"a,b,c","b e",f
3. 行结束符
回车,换行,回车/换行 -> CR,LF,CRLF
4. 标题 的处理形式
1. 需要避免把标题当作数据行导入数据库中
2. 当导入已经存在表中时,标题可以在数据文件的列与表中的列顺序不同时帮助你匹配这些列
3. 当数据文件自动或半自动的建立新表时,标题可以作为列名。
10.1 使用load data 和mysqlimport导入数据
1. 使用load data 在某些情况下,local加载项被禁用,如果安装属于这种情况可以省略local但是必须指定文件的完整路径
mysql> show variables like '%local%';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| local_infile | ON |//这个就是开启状态
+---------------+-------+
1 row in set (0.00 sec)
使用这种方式导入数据到数据库表时,该数据表要存在的情况下才让其导入数据信息:
mysql> load data local infile 'e:/date_val' into table date_val;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to
your MySQL server version for the right syntax to use near '' at line 1
mysql> load data local infile 'e:/date_val.sql' into table date_val;
Query OK, 52 rows affected, 207 warnings (0.05 sec)
Records: 52 Deleted: 0 Skipped: 0 Warnings: 207
2. 导入数据第二种方式:mysqlimport
C:\Users\monkey>
mysqlimport--local -uroot -p temp e:/date_val.sql
Enter password: ****
temp.date_val: Records: 52 Deleted: 0 Skipped: 0 Warnings: 207
C:\Users\monkey>mysqldump -p -uroot temp date_val > e:\date_val.sql
Enter password: ****
C:\Users\monkey
>mysql -p -uroot temp < e:\date_val.sql
Enter password: ****
C:\Users\monkey>
mysql -e "select * from t" -uroot -p temp> e:\e.txt
Enter password: ****
特性:load data 提供了许多选项来解决文章中在上面提到的问题
1. 默认情况下,load data 假定数据文件中包含与需要加载的表一样的数目的列,并且列出现的顺序也相同。
如果文件中没有包含表中所有列的值,或者顺序不对,你可以指定哪些列和这些列的顺序。
如果数据文件中包含的列比表中的少,mysql会默认添加默认值
2. load data假定数据值是用制表符分开,而行是使用换行符结束的,你可以为数据文件显示指定于此不同的数据格式
3. 你可以取出有可能用来括住数据值的引号,以及是什么样的引号
4. 有些特殊转义序列会被在导入中识别并且转换
5. load data 还提供了诊断信息用于分析是哪些输入值造成的问题:show warning(在cmd中用perror可以看到错误信息)
10.2 指定数据文件位置
你加载文件可以位于发出load data 语句所在的客户端主机或者服务器端主机中。默认是在服务器下
但是有写情况下并不适合:
1. 当你远程登录mysql数据库,并且没有能力向服务器所在的主机中传送文件时,你就没办法传送文件到服务器
2. 即使你有服务器账户,但是还需要具有file权限,需要待加载文件任意可读并位于默认数据库的数据目录下
幸运的是有load data local infile 来加载位于客户机上的文件,注意啊local关键字默认情况下是被禁止的,可以通过
--local-infile选项来打开它。
如果load data 没有local选项那么mysql读取的方式只有在服务器上定位文件
1. 如果给定的是绝对路径,那么就直接读取文件就是
2. 相对路径,就会在默认数据库的数据目录下查找文件
C:\Users\monkey>
mysqlimport --local -uroot -p temp date_val.sql
Enter password: ****
mysqlimport: Error: 2, File
'C:\Users\monkey\date_val.sql' not found (Errcode: 2), when using table: date_val
C:\Users\monkey>
mysqlimport -uroot -p temp date_val.sql
Enter password: ****
你们从上面的错误中你会发现:假如加了--local那么服务器就会把这次文件搜索针对客户端的默认路径进行搜索。
假如没有local那么服务器就会在服务器数据文件目录的数据库目录中查找文件
|
mysql> load data infile 'temp/date_val.sql' into table date_val; mysql> load data infile 'date_val.sql' into table date_val; 上面的两句话是等价的,都是从服务器数据文件目录的数据库目录中查找文件 mysql> load data local infile 'e:/date_val.sql' into table date_val; Query OK, 52 rows affected, 207 warnings (0.08 sec) Records: 52 Deleted: 0 Skipped: 0 Warnings: 207
|
注意:
1. load data 加载文件到非默认的数据库中,那么就在表名前面指定数据库名称
2. load data在数据文件名称和要加载的表名称之间没有约定,而mysqlimport则在数据文件与表名之间进行约定,
它使用文件名最后一部分作为表的名称。
mysqlimport -uroot -p temp
date_val
.sql
3. 在window下命名数据文件:window都是通过'\'来划分路径的,但是在mysql中'\'代表的转义字符来看待,所以在书写路径是:\\或/
当sql的
NO_BACKSLASH_ESCAPES模式被打开,'\'就不再具有特殊意义
10.3 指定数据文件的结构
问题:假如我们要导入的数据文件格式不是load data格式时? ->可以通过fields 和 lines来指定数据格式。
在默认的情况下,load data会默认使用换行符终止多行,使用制表符分开数据的值。这种方式可以通过fields 和 lines来进行改变
假如要求:使用:来分隔数据值,使用回车结束行。(终止符可以有多个)
load data local infile '文件路径' into table 表名
fields terminated by ':' //终止之意(该子句必须在第一位)
lines terminated by '\r'
starting by '一个或多个字符'//用来指定每行中间剥除部分内容的序列
注意:对于starting by 来说,每一行在给定序列之前的任何内容都将被剥除,
例如:你指定starting by 'X' 那么在输入行以'abcX'开头时,所有这四个字符都将被剥除。
假如是针对mysqlimport来说:
mysqlimport --local --field-terminated-by=":" --lines-terminated-by="\r" 数据库名 文件名
这里面的选项次数对导入没有影响。
你还可以使用十六进制作为分隔符:制表:
0x09换行:
0x0a
mysqlimport --local --field-terminated-by=0x09 --lines-terminated-by=0x0a 数据库 文件名
之所以要附加这些信息是因为服务器在读取文件的时候根本不知道哪些字符代表域/行的终结符,load data只会通过默认的方式进行分隔
而这种分隔不是所有的数据文件都去服从的,及时服从了也会出现意想不到的问题:
1.ftp在不同的操作系统之间以文本的方式而不是二进制方式进行文件传递,此时文件的结束符会被改变,
假如您的制表界定和换行借宿的数据,文件在unix系统环境变量中使用load data语句默认设置成功加载进mysql数据库中,
但是使用ftp拷贝到win下,里面的换行符会被换成回车换行,所以只有添上附加信息才可以。
2. 当数据文件通过电子邮件时,邮件软件可能会打断长一点的行或者转换结束符序列。这也会影响
10.4 处理引号和特殊字符
问题:当数据文件中包括引用值或者转义字符
解决方案:告知load data当心引用和转义字符.
fields子句可以指定除terminated by 之外的其他格式化选项。load data默认情况下会假定值未被引用,
并且它会将'\'解释为转义字符。要显示的表示值引用字符,使用 enclosed by ; mysql在输入处理期间会将该字符从数据值的尾部剥除。
要改变默认的默认字符,使用 escaped by。
fields terminated by ',' enclosed by '"'
//fieldsby 中的(enclosed by ,terminated by ,escaped by)无序
terminated by 序列可以任意顺序表现,如果数据值在输入行内被类似于*@*之类字符分开,可以:fields terminated by '*@*'
要完全禁止转义字符处理,可以指定一个空的转义序列:fields escapse by ' '
当你指定 enclosed by 以表明哪个引用字符应从数据值中剥离时,也可能在数据值中通过对其进行
成双处理或者在前面
添加转义字符来包含引用
字符,例如:如果引用和转义字符分别是:“和\ "a
" "b
\"c" -> a"b"c
对于mysqlimport ,用于指定引用和转义值的相关命令:--fields-enclosed-by 和 --fields-escaped-by
注:当使用包含引号或反斜线或其他的在于你的命令解释器来说是特殊的字符的mysqlimport选项中,记住可能需要进行引用或转义引号或转义字符
10.5 导入csv文件
怎样导入一个csv文件该文件的数据文件:包含以','作为数据域的分隔,并且以'"'作为引用。
例如:包含以回车换行字符对结尾的行的csv文件tab1.txt可以使用load data 载入到数据库中
1. load data local infile tab1.txt into table tab1
fields enclosed by '"' terminated by ','
lines terminated by '\r\n'
2. mysqlimport --local --fileds-enclosed-by="
\"" --fields-terminated-by=","
--lines-terminated-by="\r\n" 数据库 tab1.txt
10.6 读取不同操作系统的文件
问题:不同的操作系统的结束序列不同
解决:上面的问题就是引导出来了为什么load data 有个lines terminated by的原因。
注意一点:在unix中使用换行符('\n')作为行的结束符,当被用移植到别的系统中那么换行符就变成了'\r\n'
假如你的terminated by 还是 '\n'就不行了,所以额外的添加:terminated by '\r\n'才行
10.7 处理重复的键值
load data local infile ‘文件路径’ replace/ignore into table 表名
mysqlimport --local --ignore/--replace 数据库名 文件路径
10.8 获取关于错误输入数据的诊断信息
show warning()
10.9 跳过数据文件行
load data local infile into table 文件 ignore
nlines;//跳过多少行
mysqlimport --local --ignore-lines=n 数据库 文件路径
10.10 指定输入列顺序
例如:数据列 a,b,c 而表列为c,b,a
load data local infile into table 文件 (c,b,a)
mysqlimport --local --clolumns=c,b,a 数据库名 文件路径
10.11 在插入输入值之前对数据文件进行
预处理
load data 可以在插入数据文件进行有限的预处理。可以使你在输入数据前将其将匹配合适的列-值
例子:表格
mysql> show columns from t;
+------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| dt | datetime | YES | | NULL | |
| last_name | varchar(30) | YES | | NULL | |
| first_name | varchar(30) | YES | | NULL | |
| weight_kg | float | YES | | NULL | |
| st_abbrev | char(2) | YES | | NULL | |
+------------+-------------+------+-----+---------+-------+
数据
Date Time Name Weigh State
2006-09-01 12:00:00 Bill Wills 200 Nevada
2006-09-01 13:00:00 Jeff Deft 150 Oklahoma
2006-09-01 14:00:00 Bob Hobbs 225 Utah
mysql> load data local infile 'C:\\ProgramData\\MySQL\\MySQL Server 5.5\\data\\temp\\data.txt'
into table t ignore 1 lines
-> (@date,@time,@name,@weight,@state)
-> set dt=concat(@date,' ',@time),
-> first_name=substring_index(@name,' ',-1),
-> last_name=substring_index(@name,' ',1),
-> weight_kg=@weight*0.66,
-> st_abbrev=upper(left(@state,2));
结果:
+---------------------+-----------+------------+-----------+-----------+
| dt | last_name | first_name | weight_kg | st_abbrev |
+---------------------+-----------+------------+-----------+-----------+
| 2006-09-01 12:00:00 | Bill | Wills | 132 | NE |
| 2006-09-01 13:00:00 | Jeff | Deft | 99 | OK |
| 2006-09-01 14:00:00 | Bob | Hobbs | 148.5 | UT |
+---------------------+-----------+------------+-----------+-----------+
10.12 忽略数据文件列
如果列位于输入行的尾部的多余的列易于处理,直接忽略就可以了,最多会出现一些警告而已,假如是想跳过中间的列可以使用如下方式:
例子:想把unix下的/etc/passwd中的信息载入
account:password:UID:GID:GECOS:directory:shell
create table pwd(
account varchar(20),
uid int,
gid int,
gecos varchar(20),
directory char(20),
shell varchar(20)
);
使用load data方式导入数据:
load data local infile '/etc/password' into table pwd fields terminated by ':'
(account,@pwd,uid,gid,gecos,directory,shell);
使用mysqlimport 方式导入数据:
mysqlimport --local --columns="account,@pwd,uid,gid,gecos,direcotry,shell"
--fields-terminated-by=":" 数据库 文件路径
10.13 从mysql中导出查询结果
1. 使用select...into outfile语句导出
例如:把密码表中数据信息导出
select * from pwd into outfile '/tmp/pwd.txt'
fields terminated by ',' enclosed by '"'
lines terminated by '\r\n'
该方式中的属性:
1. 输出文件直接由mysql服务器创建,所以文件名应该表明你想在服务器主机某个位置创建文件
2. 你必须拥有服务器的file权限来执行select inyo
3. 输出文件必须不存在
4. 你应该有服务器的账户和密码或者有某种方式获取到主机上的文件,否则输出文件将毫无意
5. 在unix下,文件被创建为全局可读,且为执行mysql服务器的账户拥有。尽管你有读能力,但没删除和修改能力
2.使用mysql客户端导出文件
由于select...into outfile将数据文件写到服务器的文件中,那么假如没有file权限你是做不了导出的,所以所以
必须使用其他应用程序来执行一个select语句并将输出重定向到一个文件中。
mysql -e "select * from pwd" --skip-column-names 数据库 >pwd.txt
注:1. -e选项指定执行的语句,--skip-column-names表示mysl不要输入通常位于语句输出前部的列名
2. mysql默认会把null值书写成字符串'NULL'根据你想输出的的格式做预后处理
通过将输出结果送到一个后期过滤器,可以生成想要的方式
例如:要用#字符作为分界符,将所有的制表符转为#符号
mysqlimport --skip-column-names -e "your exper "
|sed -e "s/ TAB /#/g" > output_file
你也可以使用tr来完成此目的,虽然词工具的不同实现语法有变化
mysqlimport --skip-column-names -e "your exper"
| tr "\t" "#" > output_file
10.14 将表导出为文本文件
通过mysqldump程序用于拷贝或者备份表和数据库,可以写成数据文件,或者重建表行语句集
为了将表导出为一个数据文件,必须加上--tab:标识你希望mysql服务器主机上希望写上文件目录(必须存在,服务器不会创建)
mysql使用表名+.txt后缀创建表名,该方式类似于select..into outfile
如果删除了--no-create-info 那么还会创建一个表名+.sql创建表信息文件
mysqldump和mysqlimport的格式化描述符是一样的
10.15 以sql格式导出表内容或定义
mysqldump 数据库 表名 > 文件路径
提示:前面的mysqldump输出实际上是使用了--skip-extended-insert 选项生成的,他会使每行被写成独立的一行,如果去除
会变成一行来显示。
想导出所有数据库所有表:mysqldump --all-databases > 文件名 ;这样会在文件写create database use database 等信息
还有控制格式的:
1. --no-create-info :压缩create tables语句,当你仅仅是想导出表的内容
2. --no-data :压缩insert语句,当你仅仅想导出表定义时
3. --add-drop-table :为每个create table语句生成一个drop table语句。这对于生成一个以后可以用于从头在建表文件来说好用
4. --no-create-db : 压缩--data-database 选项通常锁生成的create database语句
注意:当用mysqldump导出的且不带--tab数据文件不能使用mysqlimport语句导入到数据库中,只有通过mysql来导入
10.16 将表或数据库拷贝到另外一个服务器
使用管道把mysqldump 与mysql 建立连接,也可以使用中间文件
1. mysqldump temp t | mysql -h 主机名 数据库
C:\Users\monkey>mysqldump
-uroot
-proottemp t |mysql -h localhost -uroot -p sjxy_ess
Enter password: ****
2. mysqldump temp t > t.txt 拷贝文件到远程文件中 mysql 数据库 < t.txt
3. 通过ssh来拷贝数据库文件到另外服务器中
mysqldump -uroot -proot temp t |ssh -h localhost mysql -uroot -p sjxy_ess
10.18 将数据文件从一种格式转化为另外一种格式
.....
10.19
.....//该部分以后再学习,因为用到了perl语言
10.20 使用sql模式(是一群模式的集合)来控制错误的输入数据处理
通过sql模式控制服务器的严格程度,意思就是说:严格系数大了原本是警告的插入语句就会显示为错误的信息
模式可以设置:set sql_mode='strict_all_tables,....';
查看模式:select @@sql_mode
这些设置是针对于会话级别变量值,所以仅仅在一个连接上起作用,也可以设置所有会话都有效:set global sql_mode='';
mysql> select * from information_schema.
session_variableswhere variable_name like '%mode%';
+--------------------------+----------------------------------------------------------------+
| VARIABLE_NAME | VARIABLE_VALUE |
+--------------------------+----------------------------------------------------------------+
| INNODB_STRICT_MODE | OFF |
| INNODB_AUTOINC_LOCK_MODE | 1 |
| SLAVE_EXEC_MODE | STRICT |
|
SQL_MODE| STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+--------------------------+----------------------------------------------------------------+
4 rows in set (0.00 sec)
mysql> select * from information_schema.
global_variableswhere variable_name like '%mode%'
+--------------------------+----------------------------------------------------------------+
| VARIABLE_NAME | VARIABLE_VALUE |
+--------------------------+----------------------------------------------------------------+
| INNODB_STRICT_MODE | OFF |
| INNODB_AUTOINC_LOCK_MODE | 1 |
| SLAVE_EXEC_MODE | STRICT |
|
SQL_MODE| STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+--------------------------+----------------------------------------------------------------+
4 rows in set (0.00 sec)
`VARIABLE_VALUE` varchar(1024) DEFAULT NULL//该句是全局变量的值列,通过他来看sql_mode是一个以,分隔的字符串
10.21 验证并转换数据
- 验证数据值以确定他们对于你想将他们存储到的数据是合法的。例如:日期格式:CCYY-MM-DD
- 格式化数据格式
- 识别文件中的特殊只的必要的。例如:用一个不会出现的在文件中的值代表NULL这是非常常见的