技术分享 | MySQL Load Data 的多种用法

甲辰神孟非卿
• 阅读 3321
作者:余振兴

爱可生 DBA 团队成员,熟悉 Oracle、MySQL、MongoDB、Redis,最近在盘 TiDB,擅长架构设计、故障诊断、数据迁移、灾备构建等等。负责处理客户 MySQL 及我司自研 DMP 数据库管理平台日常运维中的问题。热衷技术分享、编写技术文档。

本文来源:原创投稿

* 爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。

本文目录

一、LOAD 基本背景

二、LOAD 基础参数

三、LOAD 示例数据及示例表结构

四、LOAD 场景示例

  • 场景 1. LOAD 文件中的字段比数据表中的字段多
  • 场景 2. LOAD 文件中的字段比数据表中的字段少
  • 场景 3. LOAD 生成自定义字段数据
  • 场景 4. LOAD 定长数据

五、LOAD 总结

LOAD 基本背景

我们在数据库运维过程中难免会涉及到需要对文本数据进行处理,并导入到数据库中,本文整理了一些导入导出时常见的场景进行示例演示。

LOAD 基础参数

文章后续示例均使用以下命令导出的 csv 格式样例数据(, 逗号做分隔符,以 " 双引号作为界定符)
-- 导出基础参数
select * into outfile '/data/mysql/3306/tmp/employees.txt'
character set utf8mb4
fields terminated by ','
enclosed by '"'
lines terminated by '\n'
from employees.employees limit 10;

-- 导入基础参数
load data infile '/data/mysql/3306/tmp/employees.txt'
replace into table demo.emp
character set utf8mb4
fields terminated by ','
enclosed by '"'
lines terminated by '\n'
...

LOAD 示例数据及示例表结构

以下为示例数据,表结构及对应关系信息
-- 导出的文件数据内容
[root@10-186-61-162 tmp]# cat employees.txt
"10001","1953-09-02","Georgi","Facello","M","1986-06-26"
"10002","1964-06-02","Bezalel","Simmel","F","1985-11-21"
"10003","1959-12-03","Parto","Bamford","M","1986-08-28"
"10004","1954-05-01","Chirstian","Koblick","M","1986-12-01"
"10005","1955-01-21","Kyoichi","Maliniak","M","1989-09-12"
"10006","1953-04-20","Anneke","Preusig","F","1989-06-02"
"10007","1957-05-23","Tzvetan","Zielinski","F","1989-02-10"
"10008","1958-02-19","Saniya","Kalloufi","M","1994-09-15"
"10009","1952-04-19","Sumant","Peac","F","1985-02-18"
"10010","1963-06-01","Duangkaew","Piveteau","F","1989-08-24"

-- 示例表结构
SQL > desc demo.emp;
+-------------+---------------+------+-----+---------+-------+
| Field       | Type          | Null | Key | Default | Extra |
+-------------+---------------+------+-----+---------+-------+
| emp_no      | int           | NO   | PRI | NULL    |       |
| birth_date  | date          | NO   |     | NULL    |       |
| first_name  | varchar(16)   | NO   |     | NULL    |       |
| last_name   | varchar(16)   | NO   |     | NULL    |       |
| fullname    | varchar(32)   | YES  |     | NULL    |       | -- 表新增字段,导出数据文件中不存在
| gender      | enum('M','F') | NO   |     | NULL    |       |
| hire_date   | date          | NO   |     | NULL    |       |
| modify_date | datetime      | YES  |     | NULL    |       | -- 表新增字段,导出数据文件中不存在
| delete_flag | char(1)       | YES  |     | NULL    |       | -- 表新增字段,导出数据文件中不存在
+-------------+---------------+------+-----+---------+-------+

-- 导出的数据与字段对应关系
emp_no     birth_date    first_name   last_name    gender  hire_date
"10001"  "1953-09-02"  "Georgi"     "Facello"    "M"    "1986-06-26"
"10002"  "1964-06-02"  "Bezalel"    "Simmel"     "F"    "1985-11-21"
"10003"  "1959-12-03"  "Parto"      "Bamford"    "M"    "1986-08-28"
"10004"  "1954-05-01"  "Chirstian"  "Koblick"    "M"    "1986-12-01"
"10005"  "1955-01-21"  "Kyoichi"    "Maliniak"   "M"    "1989-09-12"
"10006"  "1953-04-20"  "Anneke"     "Preusig"    "F"    "1989-06-02"
"10007"  "1957-05-23"  "Tzvetan"    "Zielinski"  "F"    "1989-02-10"
"10008"  "1958-02-19"  "Saniya"     "Kalloufi"   "M"    "1994-09-15"
"10009"  "1952-04-19"  "Sumant"     "Peac"       "F"    "1985-02-18"
"10010"  "1963-06-01"  "Duangkaew"  "Piveteau"   "F"    "1989-08-24"

LOAD 场景示例

场景 1. LOAD 文件中的字段比数据表中的字段多

只需要文本文件中部分数据导入到数据表中
-- 临时创建2个字段的表结构
SQL > create table emp_tmp select emp_no,hire_date from emp;
SQL > desc emp_tmp;
+-----------+------+------+-----+---------+-------+
| Field     | Type | Null | Key | Default | Extra |
+-----------+------+------+-----+---------+-------+
| emp_no    | int  | NO   |     | NULL    |       |
| hire_date | date | NO   |     | NULL    |       |
+-----------+------+------+-----+---------+-------+

-- 导入数据语句
load data infile '/data/mysql/3306/tmp/employees.txt'
replace into table demo.emp_tmp
character set utf8mb4
fields terminated by ','
enclosed by '"'
lines terminated by '\n'
(@C1,@C2,@C3,@C4,@C5,@C6) -- 该部分对应employees.txt文件中6列数据
-- 只对导出数据中指定的2个列与表中字段做匹配,mapping关系指定的顺序不影响导入结果
set hire_date=@C6,
    emp_no=@C1; 

-- 导入数据结果示例
SQL > select * from emp_tmp;
+--------+------------+
| emp_no | hire_date  |
+--------+------------+
|  10001 | 1986-06-26 |
|  10002 | 1985-11-21 |
|  10003 | 1986-08-28 |
|  10004 | 1986-12-01 |
|  10005 | 1989-09-12 |
|  10006 | 1989-06-02 |
|  10007 | 1989-02-10 |
|  10008 | 1994-09-15 |
|  10009 | 1985-02-18 |
|  10010 | 1989-08-24 |
+--------+------------+
10 rows in set (0.0016 sec)

场景 2. LOAD 文件中的字段比数据表中的字段少

表字段不仅包含文本文件中所有数据,还包含了额外的字段
-- 导入数据语句
load data infile '/data/mysql/3306/tmp/employees.txt'
replace into table demo.emp
character set utf8mb4
fields terminated by ','
enclosed by '"'
lines terminated by '\n'
(@C1,@C2,@C3,@C4,@C5,@C6) -- 该部分对应employees.txt文件中6列数据
-- 将文件中的字段与表中字段做mapping对应,表中多出的字段不做处理
set emp_no=@C1,
      birth_date=@C2,
      first_name=@C3,
      last_name=@C4,
      gender=@C5,
      hire_date=@C6;

技术分享 | MySQL Load Data 的多种用法

场景 3. LOAD 生成自定义字段数据

从场景 2 的验证可以看到,emp 表中新增的字段 fullname,modify_date,delete_flag 字段在导入时并未做处理,被置为了 NULL 值,如果需要对其进行处理,可在 LOAD 时通过 MySQL支持的函数 或给定 固定值 自行定义数据,对于文件中存在的字段也可做函数处理,结合导入导出,实现简单的 ETL 功能,如下所示:
-- 导入数据语句
load data infile '/data/mysql/3306/tmp/employees.txt'
replace into table demo.emp
character set utf8mb4
fields terminated by ','
enclosed by '"'
lines terminated by '\n'
(@C1,@C2,@C3,@C4,@C5,@C6)                                                     -- 该部分对应employees.txt文件中6列数据

-- 以下部分明确对表中字段与数据文件中的字段做Mapping关系,不存在的数据通过函数处理生成(也可设置为固定值)
set emp_no=@C1,
      birth_date=@C2,
      first_name=upper(@C3),                                                     -- 将导入的数据转为大写
      last_name=lower(@C4),                                                      -- 将导入的数据转为小写
      fullname=concat(first_name,' ',last_name),             -- 对first_name和last_name做拼接
      gender=@C5,
      hire_date=@C6 ,
      modify_date=now(),                                                        -- 生成当前时间数据
      delete_flag=if(hire_date<'1988-01-01','Y','N'); -- 对需要生成的值基于某一列做条件运算

技术分享 | MySQL Load Data 的多种用法

场景 4. LOAD 定长数据

定长数据的特点如下所示,可以使用函数取出字符串中固定长度来生成指定列数据
SQL > select 
    c1 as sample_data,
    substr(c1,1,3)  as c1,
    substr(c1,4,3)  as c2,
    substr(c1,7,2)  as c3,
    substr(c1,9,5)  as c4,
    substr(c1,14,3) as c5,
    substr(c1,17,3) as c6 from t1
    
*************************** 1. row ***************************
sample_data: ABC余振兴CDMySQLEFG数据库
         c1: ABC
         c2: 余振兴
         c3: CD
         c4: MySQL
         c5: EFG
         c6: 数据库
定长数据导入需要明确每列数据占用的字符个数,以下直接使用 rpad 对现有的表数据填充空格的方式生成定长数据用作示例使用
-- 生成定长数据
SQL > select 
                concat(rpad(emp_no,10,' '),
          rpad(birth_date,19,' '),
          rpad(first_name,14,' '),
          rpad(last_name,16,' '),
          rpad(gender,2,' '),
          rpad(hire_date,19,' ')) as fixed_length_data 
      from employees.employees limit 10;

+----------------------------------------------------------------------------------+
| fixed_length_data                                                                |
+----------------------------------------------------------------------------------+
| 10001     1953-09-02         Georgi        Facello         M 1986-06-26          |
| 10002     1964-06-02         Bezalel       Simmel          F 1985-11-21          |
| 10003     1959-12-03         Parto         Bamford         M 1986-08-28          |
| 10004     1954-05-01         Chirstian     Koblick         M 1986-12-01          |
| 10005     1955-01-21         Kyoichi       Maliniak        M 1989-09-12          |
| 10006     1953-04-20         Anneke        Preusig         F 1989-06-02          |
| 10007     1957-05-23         Tzvetan       Zielinski       F 1989-02-10          |
| 10008     1958-02-19         Saniya        Kalloufi        M 1994-09-15          |
| 10009     1952-04-19         Sumant        Peac            F 1985-02-18          |
| 10010     1963-06-01         Duangkaew     Piveteau        F 1989-08-24          |
+----------------------------------------------------------------------------------+

-- 导出定长数据
select 
                concat(rpad(emp_no,10,' '),
          rpad(birth_date,19,' '),
          rpad(first_name,14,' '),
          rpad(last_name,16,' '),
          rpad(gender,2,' '),
          rpad(hire_date,19,' ')) as fixed_length_data 
into outfile '/data/mysql/3306/tmp/employees_fixed.txt'
character set utf8mb4
lines terminated by '\n'
from employees.employees limit 10;

-- 导出数据示例
[root@10-186-61-162 tmp]# cat employees_fixed.txt
10001     1953-09-02         Georgi        Facello         M 1986-06-26
10002     1964-06-02         Bezalel       Simmel          F 1985-11-21
10003     1959-12-03         Parto         Bamford         M 1986-08-28
10004     1954-05-01         Chirstian     Koblick         M 1986-12-01
10005     1955-01-21         Kyoichi       Maliniak        M 1989-09-12
10006     1953-04-20         Anneke        Preusig         F 1989-06-02
10007     1957-05-23         Tzvetan       Zielinski       F 1989-02-10
10008     1958-02-19         Saniya        Kalloufi        M 1994-09-15
10009     1952-04-19         Sumant        Peac            F 1985-02-18
10010     1963-06-01         Duangkaew     Piveteau        F 1989-08-24

-- 导入定长数据
load data infile '/data/mysql/3306/tmp/employees_fixed.txt'
replace into table demo.emp
character set utf8mb4
fields terminated by ','
enclosed by '"'
lines terminated by '\n'
(@row)  -- 对一行数据定义为一个整体
set emp_no            = trim(substr(@row,1,10)),-- 使用substr取前10个字符,并去除头尾空格数据
      birth_date    = trim(substr(@row,11,19)),-- 后续字段以此类推
      first_name    = trim(substr(@row,30,14)),
      last_name        = trim(substr(@row,44,16)),
      fullname        = concat(first_name,' ',last_name),     -- 对first_name和last_name做拼接
      gender            = trim(substr(@row,60,2)),
      hire_date        = trim(substr(@row,62,19)),
      modify_date    = now(),
      delete_flag = if(hire_date<'1988-01-01','Y','N'); -- 对需要生成的值基于某一列做条件运算

技术分享 | MySQL Load Data 的多种用法

LOAD 总结

1.默认情况下导入的顺序以文本文件 列-从左到右,行-从上到下 的顺序导入

2.如果表结构和文本数据不一致,建议将文本文件中的各列依次顺序编号并与表中字段建立 mapping 关系,以防数据导入到错误的字段

3.对于待导入的文本文件较大的场景,建议将文件 按行拆分 为多个小文件,如用 split 拆分

4.对文件导入后建议执行以下语句验证导入的数据是否有 Warning,ERROR 以及导入的数据量

  • GET DIAGNOSTICS @p1=NUMBER,@p2=ROW_COUNT;
  • select @p1 AS ERROR_COUNT,@p2 as ROW_COUNT;

5.文本文件数据与表结构存在过大的差异或数据需要做清洗转换,建议还是用专业的 ETL 工具或先粗略导入 MySQL 中再进行加工转换处理

点赞
收藏
评论区
推荐文章
Easter79 Easter79
3年前
SQLServer迁移至MySQL
SQLServer迁移至MySQLSQLServer迁移至MySQL应该有很多种迁移方案,我用的方案是使用工具:NavicatPremium。假设我们现在要把192.168.3.126(SQLServer数据库)上的P2PSite数据库迁移至192.168.3.106(MySQL数据库)步骤如下在192.168.3.106(MySQL)
Easter79 Easter79
3年前
TiDB 在 58 集团的应用与实践
作者介绍:刘春雷,58集团高级DBA,负责MySQL和TiDB的运维工作,TUGAmbassador。58集团业务种类繁多,目前包括的业务有58同城、赶集网、安居客、58金融公司、中华英才网、驾校一点通等,数据库种类包括MySQL、Redis、MongoDB、ES、TiDB。我们自己构建了“58云DB平台”,整合
Stella981 Stella981
3年前
SQLServer迁移至MySQL
SQLServer迁移至MySQLSQLServer迁移至MySQL应该有很多种迁移方案,我用的方案是使用工具:NavicatPremium。假设我们现在要把192.168.3.126(SQLServer数据库)上的P2PSite数据库迁移至192.168.3.106(MySQL数据库)步骤如下在192.168.3.106(MySQL)
Wesley13 Wesley13
3年前
Oracle:如果表存在
我正在为Oracle数据库编写一些迁移脚本,并且希望Oracle有类似MySQL的IFEXISTS结构。具体来说,每当我想在MySQL中删除表时,我都会这样做DROPTABLEIFEXISTStable_name;这样,如果表不存在,DROP不会产生错误,脚本可以继续。Oracle是否有类似的机制?
Wesley13 Wesley13
3年前
Mysql迁移到highgoDB如何实现ID自增长
目录环境文档用途详细信息环境系统平台:MicrosoftWindows(64bit)2012版本:5.6.4文档用途Mysql数据库迁移到HighGo数据库后,原Mysql表中自增长的ID如何保持自增长?详细信息分两种情况进行处理,具体如下:(1)数据库中已经存在表(tab1),而且已经有数据,而且
Stella981 Stella981
3年前
Linux下简单的MySQL操作
在前面两个章节中已经介绍过MySQL的安装了,但是光会安装还不够,还需要会一些基本的相关操作。当然了,关于MySQL的内容也是非常多的,只不过对于linux系统管理员来讲,一些基本的操作已经可以应付日常的管理工作了,至于更高深的那是DBA(专门管理数据库的技术人员)的事情了。【更改mysql数据库root的密码】首次进入数据库是不
Wesley13 Wesley13
3年前
thinkphp 基本配置
12returnarray(34//定义数据库连接信息5'DB\_TYPE''mysql',//指定数据库是mysql67'DB\_HOST''localhost',89'DB\_NAME''uchome',//数据库名1011'DB\_USER''root
Wesley13 Wesley13
3年前
2014新炬实习岗位招聘
2014新炬实习岗位招聘Oracle工程师/初级DBA岗位职责:1、日常维护、故障处理,保障系统的健康稳定运行;2、快速响应用户需求,提供数据库技术支持;3、书写技术文档,总结工作经验和故障处理方案。岗位要求:1、本科或以上学历优秀应届生,计算机或相关专业,喜爱数据库技术者;2、熟系数据库体系结构;3、熟悉oracle的
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
ClickHouse技术研究及语法简介 | 京东云技术团队
本文对Clickhouse架构原理、语法、性能特点做一定研究,同时将其与mysql、elasticsearch、tidb做横向对比,并重点分析与mysql的语法差异,为有mysql迁移clickhouse场景需求的技术预研及参考。
Vitess全局唯一ID生成的实现方案 | 京东云技术团队
为了标识一段数据,通常我们会为其指定一个唯一id,比如利用MySQL数据库中的自增主键。但是当数据量非常大时,仅靠数据库的自增主键是远远不够的,并且对于分布式数据库只依赖MySQL的自增id无法满足全局唯一的需求。因此,产生了多种解决方案,如UUID,Sn
甲辰神孟非卿
甲辰神孟非卿
Lv1
未曾青梅,青梅枯萎,芬芳满地。
文章
2
粉丝
0
获赞
0