• 具体实现思路

    首先要确认sql中没有包含decode的字符串或者字段 有的话可以自行替代后再做操作
    先获取 decode的位置 然后截取出 decode括号内的部分 通过计算左右括号的数量即可截取出来
    然后再将 decode括号内的部分分为4段 然后拼接回原来的SQL 重复循环执行即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
private static String decodeTransformToCaseWhen(String sql) {
/**
* 将decode的各部分分分别存储 最后拼接
*/
List<String> strings = new ArrayList<>();
StringBuilder result = new StringBuilder(" ( case " + strings.get(0) + " when ");
int start = sql.indexOf("decode") + 6;
int left = 0, right = 0, end = 0;
/**
* 获取当前第一个decode 出现的位置和结束的位置 start是decode之后左括号 ( 起始的位置 ende是 最右边括号 ) 的位置
*/
for (int i = sql.indexOf("decode") + 6; i < sql.length(); i++) {
if (sql.charAt(i) == '(') left++;
if (sql.charAt(i) == ')') right++;
if (right != 0 && left == right) {
end = i;
break;
}
}
/**
* 截取出decode括号内的部分
*/
String subStr = sql.substring(sql.indexOf("decode") + 7, end);
left = 0;
right = 0;
int end2 = 0;//每一个,切割位置记录 为下一次切割的起始位置
for (int i = 0; i < subStr.length(); i++) {
if (subStr.charAt(i) == '(') left++;
if (subStr.charAt(i) == ')') right++;
/**
* i == subStr.length() - 1时 直接截取到最后即可
*/
if ((subStr.charAt(i) == ',' && left == right) || i == subStr.length() - 1) {
left = 0;
right = 0;
if (i == subStr.length() - 1)
strings.add(subStr.substring(end2));
else
strings.add(subStr.substring(end2, i));
end2 = i + 1;
}
}
result.append(" ( case ").append(strings.get(0)).append(" when ");
for (int i = 1; i < strings.size() - 1; i++) {
if (i % 2 == 1)
result.append(strings.get(i)).append(" ");
else if (i == strings.size() - 2) {
result.append(" then ").append(strings.get(i)).append(" else ");
} else {
result.append(" then ").append(strings.get(i)).append(" when ");
}
}
result.append(strings.get(strings.size() - 1)).append(" end ) ");
return sql.substring(0, start - 6) + result + sql.substring(end + 1);
}
  • 调用函数及测试用例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//测试用例
public static void main(String[] args) {
String sql = "select decode(substr(TIME_, 5, 6), 2, 777,\n" +
" decode(substr(nvl(B103B,0), 1, 3), 14, 23, (nvl(B103B, 0) - substr(TIME_, 0, 3)) / substr(TIME_, 4, 6))) k,\n" +
" B103B\n" +
"from user_info\n" +
"where TIME_ = '202004'";
decodeToCaseWhen(sql);
}
//循环执行 把全部decode函数都替换
public static String decodeToCaseWhen(String sql) {
String ss = sql.replaceAll("nvl", "isnull")
.replaceAll("NVL", "isnull")
.replaceAll("DECODE", "decode");
int s = ss.split("decode").length - 1;
for (int i = 0; i < s; i++) {
ss = decodeTransformToCaseWhen(ss);
}
return ss;
}