將具有多表關聯的Excel數據,通過sql語句腳本的形式,導入到數據庫
寫在前面:本文用的語言是java;數據庫是MySql;
需求:在實際項目中,經常會被客戶要求,做批量導入數據;一般的簡單的單表數據,可以直接通過Navicat的導入功能,將Excel表格信息直接導入;單實際情況是——需要導入的數據要分別保存在對應的多張表中,其中一張主表,多張關聯副表,這個時候再用Navicat的導入功能,無法滿足需求! 本文總結一種方法處理這種批量錄入多表數據;如下。
核心思路:將Excel數據表中的數據,保存到TXT中;通過腳本讀取TXT中的數據,寫成對應的sql語句;在Navicat運行sql語句,實現保存目的;
為了展示完整的操作步驟,我准備了一個簡單的業務需求:保存學生基本信息和學生選課信息;原始EXCEL數據在一張表里;需要將數據分別保存在student_info和select_class兩張數據表中
具體操作步驟:
1.准備Excel原始數據:Excel原始數據有一定的格式要求,要求每列信息必須明確(1表示選課0表示沒選),如下圖:
將Excel數據復制到TXT中,如下;
2.准備初始化數據表;
CREATE TABLE `student_info` (
`student_id` int(10) NOT NULL AUTO_INCREMENT COMMENT '學生id',
`name` varchar(10) DEFAULT NULL,
`sex` varchar(1) DEFAULT NULL,
`age` int(2) DEFAULT NULL,
PRIMARY KEY (`student_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `select_class` (
`id` int(10) NOT NULL AUTO_INCREMENT COMMENT 'id',
`student_id` int(10) DEFAULT NULL COMMENT '學生id',
`class_name` varchar(10) DEFAULT NULL COMMENT '課程名稱',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
初始化的數據表數據表,如下:
3.編寫腳本(核心步驟),代碼如下:
package com.fh.readfile; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class TestFileReadUtil { private static int Number = 0; /** * 功能:Java讀取txt文件的內容 步驟:1:先獲得文件句柄 2:獲得文件句柄當做是輸入一個字節碼流,需要對這個輸入流進行讀取 * 3:讀取到輸入流后,需要讀取生成字節流 4:一行一行的輸出。readline()。 備注:需要考慮的是異常情況 * @param filePath * 文件路徑[到達文件:如: D:\aa.txt] * @return 將這個文件按照每一行切割成數組存放到list中。 */ public static List<String> readTxtFileIntoStringArrList(String filePath) { List<String> list = new ArrayList<String>(); try { File file = new File(filePath); if (file.isFile() && file.exists()) { // 判斷文件是否存在 InputStreamReader read = new InputStreamReader(new FileInputStream(file));// 考慮到編碼格式 BufferedReader bufferedReader = new BufferedReader(read); String lineTxt = null; while ((lineTxt = bufferedReader.readLine()) != null) { list.add(lineTxt); } bufferedReader.close(); read.close(); } else { System.out.println("找不到指定的文件"); } } catch (Exception e) { System.out.println("讀取文件內容出錯"); e.printStackTrace(); } return list; } //學生基本信息sql語句模板 private static String studentMainInfoSql = "insert into student_info(student_id,name,sex,age)value(${student_id},'${name}','${sex}',${age});";//注意'${name}'需要單引號,表示是字符串,否則生成的sql語句會出錯 //學生選課信息sql語句模板 private static String selectClassInfoSql= "insert into select_class(id,student_id,class_name) value(${id},${student_id},'${class_name}');"; //Excel數據表頭 private static final String[] HEAD_ARRAY = new String[]{"Name","Sex","Age","Chinese","Math","English","Science"}; //根據表頭名稱獲取列索引索引"Name","Sex","Age","Chinese","Math","English","Science"分別是0 1 2 3 4 5 6 private static int getIndex(String headName){ for(int i=0;i<HEAD_ARRAY.length;i++){ String head = HEAD_ARRAY[i]; if(head.equals(headName)){ return i; } } return -1; } //生成學生基本信息sql語句方法 private static void createStudentInfo(List<String>lineList){ int student_id =Number;//定義student_id的起始值 for(String line:lineList){//遍歷每一行數據 student_id++; String[] array = line.split("\t");//將每一行數據根據空格拆分成數組 //將sql模板中的value值是用真實數據替換(使用replace()方法) String studentInfoSql = studentMainInfoSql.replace("${student_id}", student_id+""). replace("${name}", array[getIndex("Name")]). replace("${sex}", array[getIndex("Sex")]). replace("${age}", array[getIndex("Age")]); //打印sql語句 System.out.println(studentInfoSql); } } //生成學生選課信息sql語句 private static void createSelectClassInfo(List<String>lineList){ int student_id =Number;//定義student_id的起始值 int select_class_id =Number;//定義select_class_id的起始值 int startIndex = getIndex("Chinese");//獲取選課信息列的首列索引 int endIndex = getIndex("Science");//獲取選課信息列的末列索引 for(String line:lineList){//遍歷每一行數據 student_id++; String[] array = line.split("\t");//將每一行數據根據空格拆分成數組 for(int i=startIndex;i< (endIndex+1);i++){//遍歷每一行數據中每個課程的選擇情況 if(array[i].equals("1")){//如果是1,表示選擇該課程,要生成對應的sql語句 select_class_id++; String className =HEAD_ARRAY[i]; //生成學生選課信息sql語句 String selectClassSql = selectClassInfoSql.replace("${id}", select_class_id+""). replace("${student_id}", student_id+""). replace("${class_name}", className); //打印 語句 System.out.println(selectClassSql); } } } } //main方法,打印最終sql語句 public static void main(String[] args) { //讀取txt文件中的數據,格式是list集合 List<String> lineList = readTxtFileIntoStringArrList("txt/student.txt"); //去掉第一行數據,因為第一行數據是表頭 lineList.remove(0); //打印學生基本信息sql語句 createStudentInfo(lineList); //打印學生選課數據sql語句 createSelectClassInfo(lineList); } }
4.運行腳本,得到sql語句;如下:
insert into student_info(student_id,name,sex,age)value(1,'林俊傑','男',30);
insert into student_info(student_id,name,sex,age)value(2,'趙麗穎','女',28);
insert into student_info(student_id,name,sex,age)value(3,'胡歌','男',36);
insert into select_class(id,student_id,class_name) value(1,1,'Chinese');
insert into select_class(id,student_id,class_name) value(2,1,'Science');
insert into select_class(id,student_id,class_name) value(3,2,'Chinese');
insert into select_class(id,student_id,class_name) value(4,2,'Math');
insert into select_class(id,student_id,class_name) value(5,3,'English');
insert into select_class(id,student_id,class_name) value(6,3,'Science');
在navicat中運行sql語句,最終結果,如下;
5.總結:本案例是多表數據導入案例中最簡單的一張,但是基本思路已經表達完整;再多的關聯表,沿用select_class即可;