五、SQL 转换:Oracle 转 MySQL
五、SQL 转换:Oracle 转 MySQL
一、需求
系统需要兼容 Oracle 和 MySQL 数据库,sql 需要转化(Oracle==>MySQL);
为此写了一个工具类进行 sql 的转化,该工具类可转换大部分的 sql。(仅供参考)。
注:因为可通过数据库连接判断数据库类型,工具类难以转化的 sql 可以写两套 SQL 来兼容
二、Oracle 转换 MySQL 之前需要了解的差异
两者之间的 SQL 转换,基本上是处理以上的差异。
三、处理思路
- 1、使用栈结构对 sql 进行标准 sql 的拆分。
- 2、对拆分后的标准 sql 进行差异处理(字符串处理)。
- 处理左右连接
- 处理 || 连接符
- 处理 sql 语句中的函数差异
- 3、组合处理后的标准sql 。
/*
1、如何将复杂 sql 分解为标准 sql 语句?
思路:
使用两个堆栈对象
Stack sqlStack = new Stack();
Stack selectStack = new Stack();
sqlStack 用来存放 sql 子句;selectStack 用来存放 sql 子句起始位置。
1、将 sql 字符串转换为字符数组。
2、循环处理字符串进行分析
2-1、判断字符是否是 SQL 子句开始,是则入栈
*/
ConvertSql.java
package com.utils;
import java.util.*;
import java.util.regex.Pattern;
/**
* Oracle 语句转换为 MySQL 可执行的语句的工具类
*/
public class ConvertSql {
//SQL 不需要作转换
private final static String _SQL_HEAD_NO_CONVERT = "--_NO_CONVERT_\r\n";
//由 Oracle 转换之后得到的 MySQL
private final static String _SQL_HEAD_CONVERTED_ORACLE_TO_MYSQL = "--_CONVERTED_ORACLE_TO_MYSQL_\r\n";
private final static String _SQL_PLACEHOLDER = "__SQL__";//SQL子句占位符
private static char[] spaceList = {' '};
private static char[] spaceCharList = {
' ', ',', '>', '<', '=', '!',
'+', '-', '*', '/'};
private static String[] beginKeyList = new String[]{"SELECT", "UPDATE", "INSERT", "DELETE", "DROP"};
public static String convertSqlToMySQL(String sql) {
//1、判断 sql 是否需要转换、否:直接原格式返回
if (!isNeedConvert(sql)) {
return sql;
}
//2、进行 sql 转换
sql = sql.trim().toUpperCase();//对 sql 首尾去空格后进行 大写转换
if (sql.startsWith("UPDATE")) {
sql = processUpdateOracleToMySQL(sql);
}
//3、替换外连接:左右连接。
sql = convertLRRelation(sql);
//4、 进行 || 字符串连接的替换: ||-->concat()函数
if (sql.indexOf("||") > 0) {
sql = convertStringRelationBreakDownSql(sql);
}
return sql;
}
/**
* 分解sql为标准sql
* @param SQL
* @return
*/
private static String convertStringRelationBreakDownSql(String SQL) {
// 0 准备工作
//SQL = SQL.toUpperCase();
SQL = "(" + SQL + ")";
// SQL子句堆栈
Stack sqlStack = new Stack();
// SQL子句位置堆栈
Stack selectStack = new Stack();
// 左括句位置堆栈
Stack braceStack = new Stack();
int count=0;
int temp;
// 1 将字符串转换为字符数组
char[] array = SQL.toCharArray();
// 2 分析
for (int i = 0; i < array.length; i++) {
// 2.1 判断当前位置是否SQL子句开始,是则入栈
if (isSQLStart(array, i)) {
selectStack.push(new Integer(i));
}
//遇到左括号,则左括号入栈
if (array[i] == '(') {
braceStack.push(new Integer(i));
}
//遇到右括号,则左括号出栈
if (array[i] == ')') {
temp=((Integer)braceStack.pop()).intValue();
//如果出栈位置==SQL子句开始位置,则认为该SQL子句结束
if(temp==((Integer)selectStack.peek()).intValue()){
//select子句出栈
selectStack.pop();
//处理SQL子句,并将SQL子句入栈
SQL=convert(sqlStack,SQL,temp,i,count);
count++;
}
}
}
// 3 处理SQL子句的|| 连接符,并组装SQL
int i=1;
int subSQLLen;
String subSQL;
String parentSQL=SQL;
while(!sqlStack.empty()){
subSQL=(String)sqlStack.pop();
subSQLLen=subSQL.length();
// 3.1 调用原来的左右连接转换方法
subSQL=convertStringRelation(subSQL);
// 3.2 组装SQL
parentSQL=insertSubSQL2ParentSQL( subSQL, parentSQL,count-i,subSQLLen);
i++;
}
// 4 去掉两端()
parentSQL=parentSQL.substring(1,parentSQL.length()-1);
return parentSQL;
}
/**
* 处理字符串连接:||-->concat()函数
*
* @param sql
* @return
*/
private static String convertStringRelation(String sql) {
StringBuffer sWhere = new StringBuffer();
sql = sql.trim().toUpperCase();
//1、判断传过来的sql 是否包含 || 连接符
if(sql.indexOf("||")>0){
//1、处理 SELECT.....FROM 之间的 || 字符串连接符。
int selectIndex = sql.indexOf("SELECT");
int fromIndex = sql.indexOf("FROM");
if (sql.indexOf("||") < fromIndex&&sql.indexOf("||") >0) {// 判断|| 连接符是否在 SELECT.....FROM之间
String sfSql = sql.substring(selectIndex + 6, fromIndex);
String[] sfSqls = sfSql.split(",");
StringBuffer sfSqlNew = new StringBuffer();
for (int i = 0; i < sfSqls.length; i++) {
String sfValue = sfSqls[i];
if (sfValue.indexOf("||") > 0) {//如果存在 || 连接符
//进行 ||-->concat()函数的替换,并将替换后的函数拼接到 StringBuffer sfSqlNew中。
String s = convertConcatBetweenSelectANDFrom(sfValue);
sfSqlNew.append(s + ",");
} else {//不存在|| 连接符,也加入到 StringBuffer sfSqlNew 中。
sfSqlNew.append(sfValue + ",");
}
}
//去除最后一个逗号,并替换SELECT......FROM 之间的列。
sfSqlNew.deleteCharAt(sfSqlNew.toString().lastIndexOf(","));
sql = "SELECT " + sfSqlNew + sql.substring(fromIndex);
} else {
//2、处理 WHERE 条件中的 || 字符串连接符。
int index=sql.indexOf("||");
while (index>0){
sql=convertSql_concat2(sql);
index=sql.indexOf("||");
}
}
}
return sql;
}
/**
* 处理 WHERE 条件中的 || 连接字符串:|| -->concat() 函数
*
* @param values
* @return
*/
private static String convertConcatAfterWhere(String values) {
String[] params = values.split("\\|\\|");
StringBuffer newConition = new StringBuffer();
newConition.append("CONCAT(");
for (int i = 0; i < params.length; i++) {
newConition.append(params[i] + ",");
}
newConition.deleteCharAt(newConition.toString().lastIndexOf(","));
newConition.append(")");
return newConition.toString();
}
/**
* 处理 select......from 之间的 || 连接字符串
*
* @param sfValue
* @return
*/
private static String convertConcatBetweenSelectANDFrom(String sfValue) {
if(sfValue.indexOf("AS")>0||sfValue.indexOf("as")>0){
sfValue=sfValue.replace("AS", "");
sfValue=sfValue.replace("as", "");
}
int index = sfValue.indexOf("||");
//如果有别名,存取别名。并去掉别名
String alias = "";
int spaceIndex = sfValue.lastIndexOf(" ");
if (spaceIndex > 0 && spaceIndex > index) {//如果成立则有别名,使用AS 关键字也可用该条件进行判断。
alias = sfValue.substring(spaceIndex).trim();
sfValue = sfValue.substring(0, spaceIndex);
}
String[] params = sfValue.split("\\|\\|");
StringBuffer newConition = new StringBuffer();
newConition.append("CONCAT(");
for (int i = 0; i < params.length; i++) {
newConition.append(params[i] + ",");
}
newConition.deleteCharAt(newConition.toString().lastIndexOf(","));
newConition.append(") ");
newConition.append(alias);
return newConition.toString();
}
/**
* SQL语句左右连接转换方法:
* 思路:
* 1、分解一个复杂的SQL为多个"不含任何子句的标准SQL子句";
* 2、用原来的方法转换标准SQL子句;
*
* @param SQL
* @return
*/
private static String convertLRRelation(String SQL) {
//1、*=左外连接,=*右外连接;sql7.0 时的用法。
if (SQL.indexOf("(+)") < 0 && SQL.indexOf("(+)") < 0) {
return SQL;
}
//2、如果是 INSERT 语句,忽略对左右连接的转换。
if (SQL.startsWith("INSERT") && SQL.indexOf("VALUES") > 0) {
return SQL;
}
//3-0、准备工作
SQL = "(" + SQL + ")";
Stack sqlStack = new Stack();// SQL子句堆栈
Stack selectStack = new Stack();// SQL子句位置堆栈
Stack braceStack = new Stack();// 左括句位置堆栈
int count = 0;
int temp;
//3-1、 将字符串转换为字符数组
char[] array = SQL.toCharArray();
//3-2、 分析
for (int i = 0; i < array.length; i++) {
// 判断当前位置是否SQL子句开始,是则入栈
if (isSQLStart(array, i)) {
selectStack.push(new Integer(i));
}
//遇到左括号,则左括号入栈
if (array[i] == '(') {
braceStack.push(new Integer(i));
}
//遇到右括号,则左括号出栈
if (array[i] == ')') {
temp = ((Integer) braceStack.pop()).intValue();
//如果出栈位置==SQL子句开始位置,则认为该SQL子句结束
if (temp == ((Integer) selectStack.peek()).intValue()) {
//select子句出栈
selectStack.pop();
//处理SQL子句,并将SQL子句入栈
SQL = convert(sqlStack, SQL, temp, i, count);
count++;
}
}
}
// 4、 处理SQL子句的左/右连接,并组装SQL
int i = 1;
int subSQLLen;
String subSQL;
String parentSQL = SQL;
while (!sqlStack.empty()) {
subSQL = (String) sqlStack.pop();
subSQLLen = subSQL.length();
// 3.1 调用原来的左右连接转换方法
subSQL = processLeftRight(subSQL);
// 3.2 组装SQL
parentSQL = insertSubSQL2ParentSQL(subSQL, parentSQL, count - i, subSQLLen);
i++;
}
// 4 去掉两端()
parentSQL = parentSQL.substring(1, parentSQL.length() - 1);
return parentSQL;
}
/**
* 组装 sql
*
* @param subSQL
* @param parentSQL
* @param num
* @param subSQLLen
* @return
*/
private static String insertSubSQL2ParentSQL(String subSQL, String parentSQL, int num, int subSQLLen) {
//定位子句在父句中的开始位置
int index = parentSQL.indexOf(_SQL_PLACEHOLDER + num);
//将占位符替换为子句
parentSQL = parentSQL.substring(0, index)
+ subSQL
+ parentSQL.substring(index + subSQLLen);
return parentSQL;
}
/**
* 改进版的转换,支持多表间外连接。
* 原则:
* FROM A,B,C WHERE A.F_1 = B.F_1(+) AND B.F_2 = C.F_2(+)
* AND B.F_3(+) = '11' AND C.F_3(+) = '22'
* 转化为:
* FROM A LEFT JOIN B ON A.F_1 = B.F_1
* LEFT JOIN C ON B.F_2 = C.F_2
* WHERE B.F_3 = '11' AND C.F_3 = '22'
*
* @param sql
* @return
*/
private static String processLeftRight(String sql) {
//1、如果SQL中没有WHERE子句,则不转换,返回原sql;因为没有WHERE子句肯定没有左右连接。
if (sql.toUpperCase().indexOf("WHERE") <= 0) {
return sql;
}
//2、如果没有左右链接符号,则不转换;返回原sql。
if (sql.indexOf("(+)") < 0 && sql.indexOf("(+)") < 0) {
return sql;
}
//3、逐条读取 WHERE 条件
int index;// 存储WHERE 关键字的开始索引。
int indexend;// 存储 WHERE 条件结束位置的索引。
int indexorder;// 存储 ORDER 关键字位置的索引
index = sql.toUpperCase().indexOf(" WHERE ");
indexend = sql.toUpperCase().indexOf(" GROUP ");
indexorder = sql.toUpperCase().indexOf(" ORDER ");
String sGroup="";
String sOrderBy="";
//筛选 WHERE 关键字后的 and 条件索引结束位置。(排除 GROUP、ORDER)
if (indexend < 0)
indexend = sql.length();// 排除 GROUP
else
sGroup=sql.substring(indexend,sql.length());//记录 Group By
if (indexorder < indexend && indexorder > 0){
indexend = indexorder;// 排除 ORDER
sOrderBy=sql.substring(indexorder,sql.length());
}
int count = 1;
StringBuffer sWhere = new StringBuffer();// 存储外连接转换后的语句
StringBuffer andWhere = new StringBuffer();// 存储非表连接条件的 and 条件
//3-1、 获取 FROM 关键字后的表名,应对如果有表的别名的情况。
String vstables_alias = sql.substring(sql.toUpperCase().indexOf("FROM") + 4, index);
String[] tables_alias = vstables_alias.split(",");
//存储不需要连接的表,处理转换后表名丢失问题。
Map<String,String> fromtable = new HashMap<String,String>();
//3-2、处理WHERE .....; AND ....条件,进行左右连接的转换
while (index > 0 && index < indexend) {
int indexand;
int space;
String swhereand = "";
// 逐条读取 and 条件
indexand = sql.toUpperCase().indexOf(" AND ", index + 5);//从指定的索引处开始,返回第一次出现的指定子字符串在此字符串中的索引.
if (indexand < 0)
indexand = indexend;
swhereand = sql.substring(index, indexand).trim();
space = getOperPosM(swhereand, 0);// 分析逻辑运算符
String tablel = "", tabler = "";// 左表名、右表名
int indexl, indexr;// 存放别名引用时 . 的索引位置
// 如果 space >0 说明需要翻译该条件
if (space > 0) {
// 获取 swhereand 条件表达式左部表名。暂不考虑表的别名
indexl = swhereand.indexOf(".");
if (indexl < space && indexl > 0) {
int spacel;
spacel = getOperPosL(swhereand, 0);
if (spacel < 0 || spacel > space) spacel = 0; //逻辑符号左面部分的表名
tablel = swhereand.substring(spacel + 1, indexl).trim();
tablel = dealExistTables_Alias(tables_alias, tablel );//处理表名是别名的情况。
}
// 获取 swhereand 条件表达式右部表名。
indexr = swhereand.lastIndexOf(".");
if (indexr > space && indexr > 0) {
int spacer;
spacer = getOperPosL(swhereand, space);
if (spacer < space) spacer = space; //逻辑符号右面部分的表名
tabler = swhereand.substring(spacer + 1, indexr).trim();
tabler = dealExistTables_Alias(tables_alias, tabler );//处理表名是别名的情况。
}
}
// 如果没有获取到表名前缀 并且条件中不包含(+) 字符,则不对该条件进行进行左右连接的转换
if (tablel.length() > 0 || tabler.length() > 0) {//是否有表名前缀
//常量表达式的左右连接处理
if (tabler.length() == 0) {
//判断是否是右连接
if (swhereand.indexOf("(+)") > 0) {//是:待处理、暂不考虑
} else {//否
andWhere.append(swhereand + " ");
}
} else {
if (swhereand.indexOf("(+)") > 0) {// WHERE 条件中包含 (+) 则进行翻译
if (swhereand.indexOf("=") > swhereand.indexOf("(+)")) {// 判断是左连接还是右连接:ture 则为右连接
swhereand = swhereand.replace("(+)", "");
swhereand = swhereand.replace("AND", "");
swhereand = swhereand.replace("WHERE", "");
if(sWhere.indexOf(tablel)>=0){//处理 表名重复问题
int onIndex =sWhere.indexOf("ON",sWhere.indexOf(tablel))+2;
sWhere.insert(onIndex,swhereand+" AND ");
}else{
sWhere.append(" RIGHT JOIN " + tablel + " ON " + swhereand + " ");
}
} else {//左连接
swhereand = swhereand.replace("(+)", "");
swhereand = swhereand.replace("AND", "");
swhereand = swhereand.replace("WHERE", "");
if(sWhere.indexOf(tabler)>=0){//处理 表名重复问题
int onIndex =sWhere.indexOf("ON",sWhere.indexOf(tabler))+2;
sWhere.insert(onIndex,swhereand+" AND ");
}else{
sWhere.append(" LEFT JOIN " + tabler + " ON " + swhereand + " ");
}
}
}else{//where 条件不包含外连接(+) 符号
if(swhereand.indexOf("OR")<0){//and 条件不含 OR 逻辑运算符时
if(!fromtable.containsKey(tabler)){
fromtable.put(tabler, tabler);
}
if(!fromtable.containsKey(tablel)){
fromtable.put(tablel, tablel);
}
}
andWhere.append(swhereand + " ");
}
}
} else {
andWhere.append(swhereand + " ");
}
index = indexand;// 重新计算 index 控制循环,遍历下一个 AND 条件。
}
// 内连接需要存的表
String vs_fromtables = "";
Iterator<Map.Entry<String, String>> entries = fromtable.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<String, String> entry = entries.next();
vs_fromtables +=entry.getKey()+",";
}
//设置外连接时默认主表
if(vs_fromtables==null||vs_fromtables.equals("")){
vs_fromtables+=tables_alias[0]+",";
}
vs_fromtables=vs_fromtables.substring(0,vs_fromtables.length()-1);
String and_Where=andWhere.toString().toUpperCase();
and_Where=and_Where.indexOf("WHERE")>=0?and_Where:and_Where.replaceFirst("AND", "WHERE");
index = sql.toUpperCase().indexOf("FROM");
sql = sql.substring(0, index) + " FROM ("+vs_fromtables +")" + sWhere + and_Where+sGroup+sOrderBy;
return sql;
}
/**
* 恢复表名+别名
* @param tables_alias
* @param tablel
* @return
*/
// private static String rollbackdealExistTables_Alias(String[] tables_alias, String tablel) {
// for(int i=0;i<tables_alias.length;i++){
// if(tables_alias[i].indexOf(tablel)>=0){
// tablel=tables_alias[i];
// }
// }
// return tablel;
// }
/**
* 处理含有表别名的情况:如果and 条件中的表名是 FROM 后数据表的别名,则将表名和别名赋值给 tablel。
*
* @param tables_alias
* @param table
* @return
*/
private static String dealExistTables_Alias(String[] tables_alias, String table ) {
for (int i = 0; i < tables_alias.length; i++) {
String table_alia = tables_alias[i].trim();
int indexSpace = getOperPosL(table_alia, 0);
if (indexSpace > 0) {//如果含有空格,则有别名
String alias = table_alia.substring(indexSpace);//截取别名部分的字符串,有可能包含 AS 关键字
int aliasIndex = alias.indexOf(table, 0);
if (aliasIndex > 0&&alias.trim().length()==table.length()) {
table = table_alia;
}
}
}
return table;
}
/**
* 主要为了获取条件中的表名
* 分析 WHERE 条件中是否包含 "(", "=", ">", "<"," " 五种符号
* 如果包含则返回该 符号的索引位置。
*
* @param strSql
* @param begin
* @return
*/
private static int getOperPosL(String strSql, int begin) {
String operList[] = new String[]{
"(", "=", ">", "<", " "};
int pos = -1;
String strValue = "";
int length = strSql.length();
for (int i = begin; i < strSql.length(); i++) {
strValue = strSql.substring(i, i + 1);
for (int j = 0; j < operList.length; j++) {
if (strValue.equals(operList[j])) {
return i;
}
}
}
return pos;
}
/**
* 分析 WHERE 条件中是否包含 "=", ">", "<" 三种逻辑运算符
* 如果包含则返回该 运算符的索引位置。
*
* @param strSql
* @param begin
* @return
*/
private static int getOperPosM(String strSql, int begin) {
String operList[] = new String[]{
"=", ">", "<"};
int pos = -1;
String strValue = "";
int length = strSql.length();
for (int i = begin; i < strSql.length(); i++) {
strValue = strSql.substring(i, i + 1);
for (int j = 0; j < operList.length; j++) {
if (strValue.equals(operList[j])) {
return i;
}
}
}
return pos;
}
/**
* 抽取并转换SQL子句
*
* @param sqlStack
* @param SQL
* @param start
* @param end
* @param count
* @return
*/
private static String convert(Stack sqlStack, String SQL, int start, int end, int count) {
// 1、 从SQL中抽取SQL子句,保留SQL子句外面的壳"即...(select ... from ...)...-->...(--SQLi--)..."
String subSQL = SQL.substring(start + 1, end);
sqlStack.push(subSQL);
// 2、 并在原SQL子句位置回填子句标记
int len = subSQL.length();
int spaceCount = len - (_SQL_PLACEHOLDER.length() + 1);//(end-start-1)-(_SQL_PLACEHOLDER.length()+1);
SQL = SQL.substring(0, start + 1) + _SQL_PLACEHOLDER + count + space("_", spaceCount) + SQL.substring(end);
return SQL;
}
private static String space(String seed, int n) {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < n; i++) {
buffer.append(seed);
}
return buffer.toString();
}
/**
* 判断标准: 当前位置字符是"(" 且 后面的 Token为 "SELECT/UPDATE/INSERT等关键字"。
*
* @param array
* @param postion
* @return
*/
private static boolean isSQLStart(char[] array, int postion) {
boolean tag = false;
if (array[postion] == '(') {
// 取下一个Token
String token = getNextToken(array, postion + 1);
// 判断Token 是否为SQL子句开始关键字
for (int i = 0; i < beginKeyList.length; i++) {
if (token.toUpperCase().equals(beginKeyList[i])) {
tag = true;
break;
}
}
}
return tag;
}
/**
* 获取当前位置开始的第一个 Token
*
* @param array
* @param postion
* @return
*/
private static String getNextToken(char[] array, int postion) {
StringBuffer token = new StringBuffer();
//吃掉Token开始空格
postion = getNextTokenStartPosition(array, postion);
for (int i = postion; i < array.length; i++) {
//循环判断该字符是否Token分隔符
for (int k = 0; k < spaceCharList.length; k++) {
if (array[i] == spaceCharList[k]) {
return token.toString().trim();
}
}
//该字符不是分隔符,则认为是Token的字符
token.append(array[i]);
}
return token.toString().trim();
}
/**
* 吃空格--找到第一个非空字符位置。
*
* @param array
* @param begin
* @return
*/
private static int getNextTokenStartPosition(char[] array, int begin) {
char ch;
//1 忽略begin后面的空格-找到"标志符"的开始位置
for (int i = begin; i < array.length; i++) {
int j = 0;
for (; j < spaceList.length; j++) {
if (array[i] == spaceList[j]) {
begin++;
break;
}
}
//遇到第一个非分隔符(表明Token开始出现),则退出循环
if (j == spaceList.length) {
break;
}
}
return begin;
}
/**
* 专门处理 Update 语句
*
* @param sql
* @return
*/
private static String processUpdateOracleToMySQL(String sql) {
int index, whereIndex;
//1、对 sql 进行大写转换。
String upperSql = sql.trim().toUpperCase();
//2、如果整个语句没有 FROM 子句,则语句不进行转换;如果整个语句没有 WHERE 子句,则语句不进行转换。
index = upperSql.lastIndexOf(" FROM ");
if (index < 0) {
return sql;
}
whereIndex = upperSql.lastIndexOf(" WHERE ");
if (whereIndex < 0) {
return sql;
}
//3、如果在FROM和WHERE之间有单引号或双引号,则不进行转换。
String temp = upperSql.substring(index + 4, whereIndex);
int nValue = temp.indexOf("'");
if (nValue >= 0) {
return sql;
}
nValue = temp.indexOf("\"");
if (nValue >= 0) {
return sql;
}
//4、如果有From子句,但也有Exists,说明此UPDATE可能是标准SQL,同样不做处理。
if (upperSql.indexOf("EXISTS") > 0) {
return sql;
}
//5、如果 set field = (select ...) or = isnull((select...则不做处理。
String setclause = upperSql.substring(upperSql.indexOf(" SET ") + 5);
setclause = setclause.substring(setclause.indexOf("=") + 1); //取 = 后面的部分
setclause = setclause.replaceAll(" ", ""); //去掉所有空格 ;
if (setclause.startsWith("(SELECT") ||
setclause.startsWith("ISNULL((SELECT") ||
setclause.startsWith("ISNULL(SELECT")) {
return sql;
}
//6、默认为只要存在FROM子句,就应该存在WHERE
String tabn = sql.substring(upperSql.indexOf("UPDATE") + 6, upperSql.indexOf(" SET ")).trim();
String set = sql.substring(upperSql.indexOf(" SET ") + 5, index).trim();
String from = sql.substring(upperSql.indexOf(" FROM ") + 6, upperSql.indexOf(" WHERE ")).trim();
String astable = "";
boolean ib = checkFromTable(from, tabn);
if (ib && from.indexOf(",") > 0) {
//截取本表之后的字符
String vsTable = from.substring(from.indexOf(tabn) + tabn.length()).trim();
if (vsTable.indexOf(",") >= 0) {//如果本表后边有逗号
//看是否有别名
astable = vsTable.substring(0, vsTable.indexOf(","));
if (!astable.trim().equals("")) {//有别名
astable = astable.trim();
}
vsTable = vsTable.substring(vsTable.indexOf(",") + 1);
} else {//没有逗号的情况
astable = vsTable.trim();
vsTable = "";
}
from = from.substring(0, from.indexOf(tabn)) + vsTable;
}
String seleCol = "", setCol = "";
String where = sql.substring(upperSql.indexOf(" WHERE ") + 7).trim();
setCol += set.substring(0, index);
index = set.indexOf("=");
set = set.substring(index + 1);
while (set.trim().length() > 0) {
index = set.indexOf("=");
if (index >= 0) {
temp = set.substring(0, index);
set = set.substring(index + 1);
for (int i = temp.length(); i > 0; i--) {
if (temp.substring(i - 1, i).equals(",")) {
setCol += "," + temp.substring(i).trim();
seleCol += "," + temp.substring(0, i - 1).trim();
break;
}
}
} else {
seleCol += "," + set;
set = "";
}
}
if (setCol.startsWith(",")) {
setCol = setCol.substring(1);
}
//加( )
if (!setCol.trim().startsWith("(")) {
setCol = "(" + setCol + ")";
}
if (seleCol.startsWith(",")) {
seleCol = seleCol.substring(1);
}
temp = from;
from = "";
String alias = "";
String temp1;
while (temp.trim().length() > 0) {
index = temp.indexOf(",");
if (index >= 0) {
temp1 = temp.substring(0, index);
temp = temp.substring(index + 1);
} else {
temp1 = temp;
temp = "";
}
if (temp1.trim().length() > tabn.length() &&
tabn.equals(temp1.trim().substring(0, tabn.length())) &&
temp1.substring(tabn.length(), tabn.length() + 1).equals(" ")) {
alias = temp1.substring(tabn.length()).trim();
} else {
from += "," + temp1;
}
}
if (from.trim().length() > 0 && from.startsWith(",")) {
from = from.substring(1);
}
//where 中的 where要去掉 group 字句
String where1 = where;
if (upperSql.indexOf(" GROUP ") > 0) {
where1 = sql.substring(upperSql.indexOf(" WHERE ") + 7, upperSql.indexOf(" GROUP ")).trim();
}
sql = "update " + tabn + " " + alias + " set " + setCol +
" = ( select " + seleCol + " from " + from + " where " +
where + " ) where exists ( select 1 from " + from +
" where " + where1 + " ) ";
//替换别名
if (!astable.equals("")) {
sql = StringFunction.replaceString(sql, astable + ".", tabn + ".");
}
return sql;
}
/**
* 检查update SQL 中 from 子句中,是否包含sTable表
*
* @param sFrom
* @param sTable
* @return
*/
private static boolean checkFromTable(String sFrom, String sTable) {
int ib = sFrom.indexOf(sTable);
if (ib >= 0) {
String sRem = sFrom.substring(ib + sTable.length(), sFrom.length());
if (sRem != null && !sRem.trim().equals("")) {
if (sRem.startsWith(" ") || sRem.startsWith(",")) {
return true;
}
} else {
return true; //后面没内容 也返回真
}
}
return false;
}
/**
* 判断 SQL 是否需要转换:根据 SQL Head 标志,判断该SQL语句是否需要做跨平台语法转换
*
* @param sql
* @return
*/
private static boolean isNeedConvert(String sql) {
boolean tag = true;
//1、将所有不需要转换的HeadTag装入数组
String[] head = new String[]{
ConvertSql._SQL_HEAD_NO_CONVERT,
ConvertSql._SQL_HEAD_CONVERTED_ORACLE_TO_MYSQL
};
//2、判断 sql 是否含有 数组中的 tag 头标记。若有:则不需要转换
for (int i = 0; i < head.length; i++) {
if (sql.startsWith(head[i])) {
tag = false;
break;
}
}
return tag;
}
/**
* 处理 WHERE 条件中的 || 连接符
* @param pSql
* @return
*/
public static String convertSql_concat2(String pSql) {
String convertSql = null;
pSql=pSql+" ";// 如果 || 连接符条件在sql 的最后,则需要手工补个空格。
int idx_concat = pSql.indexOf("||");
if (idx_concat >= 0) {
int idx_space1 = -1, idx_space2 = -1, idx_data = -1;
for (int i = idx_concat - 1; i >= 0; i--) {
char cc = pSql.charAt(i);
if (Character.isSpace(cc)) {
if (idx_data != -1) {
idx_space1 = i;
break;
}
} else {
idx_data = i;
}
}
idx_data = -1;
for (int i = idx_concat + 2; i <= pSql.length() - 1; i++) {
char cc = pSql.charAt(i);
if (Character.isSpace(cc)) {
if (idx_data != -1) {
idx_space2 = i;
break;
}
} else {
idx_data = i;
}
}
String rightStr = pSql.substring(idx_space1 + 1, idx_space2);
rightStr=rightStr.replace("(","");//如果 条件中含有 左右括号则去除
rightStr=rightStr.replace(")","");
String[] strss = rightStr.split("\\|\\|");
String ss = "CONCAT(" + rightStr.replaceFirst("\\|\\|", ",") + ")";
convertSql = pSql.replaceFirst(strss[0] + "\\|\\|" + strss[1], ss);
} else {
convertSql = pSql;
}
return convertSql;
}
}
StringFunction.java
package com.utils;
import java.util.*;
public class StringFunction {
/**
* 字符串替换函数
*
* @param psStr 要进行处理的参数字符串
* @param psS 被替换的字符串
* @param psD 替换的字符串
* @return psStr 被替换后的字符串。
*/
public static String replaceString(String psStr, String psS, String psD) {
int viPos = psStr.indexOf(psS);
if (viPos < 0)
return psStr;
int viLength = psS.length();
StringBuffer vsValue = new StringBuffer();
while (viPos >= 0) {
vsValue.append(psStr.substring(0, viPos));
vsValue.append(psD);
psStr = psStr.substring(viPos + viLength);
viPos = psStr.indexOf(psS);
}
vsValue.append(psStr);
return vsValue.toString();
}
}