使用java sql parser插件Jsqlparser 实例(二)

本文介绍了如何使用JsqlParser插件解析和组装SQL语句,特别是针对SQL中的表名替换。同时,文章讨论了解决SQL语句基本语法检查和insert语句批量插入数据的方法,通过正则表达式匹配实现数据的重新组装。

开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

     JsqlParser插件用来对于SQL语句进行解析和组装,将SQL语句关键词之间的内容用List<String>进行保存,同时可以进行更改List<String>的内容后重新组装成一个新的SQL语句。项目中的需求多用于更改SQL中table name。(其实感觉用正则会更好一点) JsqlParser其实就是将sql语句各个关键词用Java类的形式进行了对应解析,包括很多函数可以让我们得到各个部分的内容 

    熟悉了Jsql插件的一些基本使用情况以后,发现还有一些不足,目前把这几天写的东西放上来了。解决一些这样的问题:

   1.给定的SQL语句是否满足基本语法问题?——我尝试将String转化为statement将Jsql的异常信息保存,并提取有效信息,返回错误单词+位置信息

   2.insert语句批量插入数据的修改————正则匹配values并保存到List<List<Stirng>>中,replace函数替换原来SQL完成重新组装。

   后面给出具体解决方法,并总结了一些知识。


  1.Jsql异常信息的抛出以及正则匹配的知识

	// 获取sql语句中的所有表名
	// 可以获取任意类型sql语句的全部表名,这里使用的select sql
	// **********传入String 得到List<String>,嵌套已测试
	public static List<String> test_select_table(String sql)
			throws JSQLParserException {
		Statement statement = (Statement) CCJSqlParserUtil.parse(sql);
		Select selectStatement = (Select) statement;
		TablesNamesFinder tablesNamesFinder = new TablesNamesFinder();
		List<String> tableList = tablesNamesFinder
				.getTableList(selectStatement);
		return tableList;
	}

	// 验证sql语法正确性,返回错误信息
	// 传入 String sql
	// ***********返回错误信息such as: “错误单词” “line 1” “column 80”
	public static String judge_type(String sql) {

		try {
			Statement statement = (Statement) CCJSqlParserUtil.parse(sql);
		} catch (JSQLParserException e) {
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			e.printStackTrace(new PrintStream(baos));
			String exception = baos.toString();
			String regEx = "Encountered(.*)";
			Pattern pat = Pattern.compile(regEx);
			Matcher mat = pat.matcher(exception);
			while (mat.find()) {
				exception = mat.group(1);
			}
			// System.out.println(exception);
			String line = "";
			String regEx2 = "line (.*),";
			pat = Pattern.compile(regEx2);
			mat = pat.matcher(exception);
			while (mat.find()) {
				line = mat.group(1);
			}
			// System.out.println(line);

			int line_num = Integer.valueOf(line).intValue();
			int indexofcolumn = exception.indexOf("column");
			String errornumber = exception.substring(indexofcolumn + 7,
					exception.length() - 1);
			int error_num = Integer.valueOf(errornumber).intValue();
			System.out.println(error_num);

			String ERROR_location = "";
			if (error_num != 1) {
				String sql_sub = sql.substring(0, error_num - 2); // 发生错误位置前面的字符串
				// 错误信息单词往往处于错误位置的前一个地方单词
				// 获取错误位置两个前面两个空格之间的单词,并保存
				sql_sub = new StringBuilder(sql_sub).reverse().toString();
				int indexofspace = sql_sub.indexOf(" ");
				String sql_error = sql_sub.substring(0, indexofspace);
				sql_error = new StringBuilder(sql_error).reverse().toString();
				ERROR_location = "\"" + sql_error + "\"" + " at line "
						+ line_num + " at column " + error_num;
			} else {
				int indexofspace = sql.indexOf(" ");
				String sql_error = sql.substring(0, indexofspace);
				ERROR_location = "\"" + sql_error + "\"" + " at line "
						+ line_num + " at column " + error_num;
			}
			return ERROR_location; // 错误信息的返回
		}
		String result = "correct";
		return result; // Jsql可以解析,返回correct
	}
总结:

1.group()组,正则子表达式概念
2.matcher,只有执行了find()方法 后,状态机matcher才是真正开始进行匹配工作的

3.捕获try catch语句中的异常信息,保存到String中去。关键函数e.printStackTrace


2..insert语句批量插入数据的修改

// insert时获取所有values(批量插入情况) insert table1(c1,c2)
	// values(v1,v2),(v11,v22),(v111,v222)
	public static List<List<String>> insert_values(String sql)
			throws JSQLParserException {
		Statement statement = CCJSqlParserUtil.parse(sql);
		String exception = statement.toString();
		System.out.println(exception);
		List<List<String>> str_values = new ArrayList<List<String>>();
		String regEx1 = "VALUES(.*)|ON DUPLICATE KEY UPDATE$";
		Pattern pat = Pattern.compile(regEx1);
		Matcher mat = pat.matcher(exception);
		while (mat.find()) {
			exception = mat.group(1).toString();
		}
		String regEx2 = "(?<=\\().*?(?=\\))";
		pat = Pattern.compile(regEx2);
		mat = pat.matcher(exception);
		while (mat.find()) {
			exception = mat.group(0).toString();
			List<String> str_list = new ArrayList<String>();
			// System.out.println(exception);
			String str = "";
			// 将Values 每一个括号内部的string 按照 ,分割开来。并加入到List<String>
			for (int i = 0, j = 0; j < exception.length() - 1; j++) {
				if (exception.charAt(j) == ',') {
					str = exception.substring(i, j);
					// System.out.println(str);
					i = j + 1;
					str_list.add(str);
				}
				if (j == exception.length() - 2) {
					str = exception.substring(i, j + 2);
					// System.out.println(str);
					str_list.add(str);
				}
			}
			// List<List<Stirng>>.add
			str_values.add(str_list);
		}
		return str_values;

	}

// 组装insert   
	//批量Values的组装,	//参数:要修改的sql语句,已经得到的新的List<List<Stirng>>
	//将原来的Values替换为新参数
	public static String build_insert_values(String sql,
			List<List<String>> str_values) throws JSQLParserException {
		//这里相当于 字符串转化大写   与  单空格间隔 的格式化,方便后面替换
		Statement statement = CCJSqlParserUtil.parse(sql);
		String exception = statement.toString();
		
		String exception_delete = "";
		String replacement = "";
		String regEx = "VALUES(.*)";
		Pattern pat = Pattern.compile(regEx);
		Matcher mat = pat.matcher(exception);
		while (mat.find()) {
			exception_delete = mat.group(1).toString();
		}
		boolean start_out = true;
		//为二维string添加  逗号和括号
		for (int i = 0; i < str_values.size(); i++) {
			boolean start_in = true;
			String brackets = "";
			for (int j = 0; j < str_values.get(i).size(); j++) {
				if (start_in == true) {
					brackets += str_values.get(i).get(j);
					// System.out.println(brackets);
					start_in = false;
				} else
					brackets += "," + str_values.get(i).get(j);
			}
			brackets = "(" + brackets + ")";
			if (start_out == true) {
				replacement = brackets;
				start_out = false;
			} else
				replacement += "," + brackets;
		}
		//最后加上分号
		replacement += ";";
		// System.out.println(replacement);
		exception = exception.replace(exception_delete, replacement);
		sql = exception;
		return sql;
	}
}



开发板推荐:天空星STM32F407VET6开发板

超高性价比 STM32主控 | 超高主频 | 一板兼容百芯 | 比赛神器 | 沉金彩色丝印

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值