oracle decode转为mysql case when,批量转换

目录

1. 业务背景:

2. 方案汇总:

1) 方案一:手工改造sql语句。

2) 方案二:增加mybatis拦截器

3) 方案三:mysql编写decode function

4) 方案四:编写程序批量替换decode

4. 重点:批量替换代码

1) 整体思路

2) 具体代码


oracle转mysql,上云,批量转换decode,decode转case when

1. 业务背景:

系统上云,原oracle需转为mysql数据库。mysql不支持decode。

系统使用mybatis框架

2. 方案汇总:

1) 方案一:手工改造sql语句。

适用性:系统较小,含有decode的sql较少。

2) 方案二:增加mybatis拦截器

方式:sql执行前变更sql,将decode变更为mysql

缺点:增加系统复杂性,改造后系统较乱。啥样的sql都有,四不像。

3) 方案三:mysql编写decode function

适用性: 因为mysql function不支持动态参数,有多少个参数就需

要传递多少个参数,所以oracle中使用的decode参数需固定。

局限性太大

4) 方案四:编写程序批量替换decode

优点:一劳永逸。

适用性:原sql中decode使用较多。

4. 重点:批量替换代码

1) 整体思路

  1. 获取系统内所有mybatis 的 sql xml文件
  2. 判断是否存在decode.
  3. 获取decode整个字符串,如:decode(a, 1, '好', 2, '坏')
  4. 获取decode内部所有条件、结果字段;如:a, 1, '好', 2, '坏'。需考虑特殊情况,如decode嵌套,decode内部有函数,内部有语句等情况

2) 具体代码

如有用,麻烦点个赞。

转载请注明出处

import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

/**
 * oracle sql语句 decode 批量替换为 case when
 *
 * @author :zhangbaoyu
 * @date :Created in 2021/5/28 下午3:41
 */
public class OracleDecodeToCaseWhenProcess {

    // 扫描文件夹
    private static final String mybatisXmlDir = "填写包含mybatis xml的目录";

    public static void main(String[] args) {
        // 所有待处理文件路径 list
        List<String> fileNameList = findMapperXmlFile();


        for (String mybatisXmlFile : fileNameList) {
            // 获取文件内容
            String xmlContent = getXmlStr(mybatisXmlFile);

            // 文件decode替换
            while (xmlContent.contains("decode") || xmlContent.contains("DECODE")) {
                // 包含大写的deocde?
                boolean upperContains = xmlContent.contains("DECODE");
                String containsDecodeStr = upperContains ? "DECODE" : "decode";

                // 取出decode内容 DECODE(STATUS_FLAG, 'S', '完成', '未完成')
                String decodeStr = getDecodeStr(xmlContent, containsDecodeStr);

                String caseWhenStr = decodeToCaseWhenStr(decodeStr);

                System.out.println("old decode = " + decodeStr);
                System.out.println("new case when = " + caseWhenStr);
                xmlContent = xmlContent.replace(decodeStr, caseWhenStr);
                writeFile(mybatisXmlFile, xmlContent);
            }
        }

        // 测试
        // String decodeToCaseWhenStr = decodeToCaseWhenStr("decode(sum(yanshou_khqt06_all),0,0,round((sum(yanshou_khqt06_all)-sum(yanshou_khqt06_over))/sum(yanshou_khqt06_all)*100,2))");
        // String decodeToCaseWhenStr = decodeToCaseWhenStr("decode(decode(tot.timeout_type, null, -1, tot.timeout_type),0,1,0)");
        
    }

    /**
     * 获取mybatis xml 文件
     *
     * @return
     */
    public static List<String> findMapperXmlFile() {
        // 待扫描文件夹
        Stack<String> waitDealDirectory = new Stack<>();
        waitDealDirectory.push(mybatisXmlDir);


        // 所有待处理文件路径 list
        List<String> fileNameList = new ArrayList<>();

        // 获取所有mybatis xml文件
        while (!waitDealDirectory.empty()) {
            String fileDir = waitDealDirectory.pop();
            File dir = new File(fileDir);
            for (File file : dir.listFiles()) {
                if (file.isFile()) {
                    // 是否是mybatis xml 文件
                    if (file.getName().lastIndexOf("Mapper.xml") != -1) {
                        fileNameList.add(file.getAbsolutePath());
                    }
                } else if (file.isDirectory()) {
                    waitDealDirectory.push(file.getAbsolutePath());
                }
            }
        }
        return fileNameList;
    }

    /**
     * 获取文件内容
     *
     * @param filePath
     * @return
     */
    public static String getXmlStr(String filePath) {
        // 文件内容读取
        File xmlFile = new File(filePath);
        StringBuffer sb = new StringBuffer();
        BufferedReader bufferedReader = null;
        try {
            bufferedReader = new BufferedReader(new FileReader(xmlFile));
            String lineStr = null;
            while ((lineStr = bufferedReader.readLine()) != null) {
                sb.append(lineStr + "\n");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != bufferedReader) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return sb.toString();
    }

    /**
     * 获取decode 内容
     *
     * @return
     */
    public static String getDecodeStr(String xmlContent, String containsDecodeStr) {
        // decode 内的符号
        Stack<String> decodeStack = new Stack<>();
        decodeStack.push(containsDecodeStr);

        // decode字符位置
        int decodeBeginIdx = xmlContent.indexOf(containsDecodeStr) + containsDecodeStr.length();

        // 基于decode index 增加的index,
        int decodeEndIdx = decodeBeginIdx + 1;
        while (!decodeStack.empty()) {
            // 获取当前字符
            String str = xmlContent.substring(decodeEndIdx - 1, decodeEndIdx);

            if ("(".contains(str)) {
                // 左括号 入栈
                decodeStack.push(str);
                decodeEndIdx++;
            } else if (")".contains(str)) {
                // 右括号,出栈,直至匹配到对应的左括号
                while (!"(".equals(decodeStack.pop())) {
                }
                // 如果栈顶  是 最开始压入栈的,直接弹出;程序结束
                if (containsDecodeStr.equals(decodeStack.peek())) {
                    decodeStack.pop();
                } else {
                    decodeEndIdx++;
                }
            } else {
                decodeEndIdx++;
            }
        }

        // 取出decode内容 DECODE(STATUS_FLAG, 'S', '完成', '未完成')
        String decodeStr = xmlContent.substring(decodeBeginIdx - containsDecodeStr.length(), decodeEndIdx);
        return decodeStr;
    }

    /**
     * decode 转换为 case when
     *
     * @return
     */
    public static String decodeToCaseWhenStr(String decodeStr) {
        // 1. 取出decode内部的内容
        int indexBegin = decodeStr.indexOf("(");
        int indexEnd = decodeStr.lastIndexOf(")");
        String decodeContent = decodeStr.substring(indexBegin + 1, indexEnd);

        // 各字段 list
        List<String> itemList = new ArrayList<>();

        // 查找字段的栈
        Stack<String> columnFindStack = new Stack<>();

        // 每个字段
        StringBuffer itemSb = new StringBuffer();

        for (int i = 1; i <= decodeContent.length(); i++) {
            String charAtStr = decodeContent.substring(i - 1, i);

            if ("(".equals(charAtStr)) {
                // 左括号 入栈
                columnFindStack.push(charAtStr);
                // 拼接字段
                itemSb.append(charAtStr);
            } else if (")".equals(charAtStr)) {
                // 右括号 匹配左括号
                while (!"(".equals(columnFindStack.pop())) {
                }
                // 拼接字段
                itemSb.append(charAtStr);
            } else if (",".equals(charAtStr) && columnFindStack.isEmpty()) {
                // 匹配','号,并且栈内为空。取出字段,并开始下一个字段获取
                itemList.add(itemSb.toString());
                itemSb = new StringBuffer();
            } else {
                // 拼接字段
                itemSb.append(charAtStr);
            }
        }

        // 最后的str
        if (StringUtils.isNotEmpty(itemSb.toString())) {
            itemList.add(itemSb.toString());
        }

        if (itemList.size() < 3) {
            System.out.println("error itemList size <3,decodeStr=" + decodeStr);
        }

        StringBuffer caseWhenSb = new StringBuffer("(case ");
        for (int i = 0; i < itemList.size(); i++) {
            String item = itemList.get(i);
            if (i == 0) {
                caseWhenSb.append(item);
            } else if (i % 2 == 1) {
                if (i == itemList.size() - 1) {
                    caseWhenSb.append(" else ").append(item);
                } else {
                    caseWhenSb.append(" when ").append(item);
                }
            } else if (i % 2 == 0) {
                caseWhenSb.append(" then ").append(item);
            }
        }
        caseWhenSb.append(" end)");

        return caseWhenSb.toString();
    }

    /**
     * 写入文件
     * @param filePath
     * @param xmlContent
     */
    public static void writeFile(String filePath, String xmlContent) {
        File f = new File(filePath);
        FileWriter fw = null;
        BufferedWriter bw = null;
        try {
            if (!f.exists()) {
                f.createNewFile();
            }
            fw = new FileWriter(f.getAbsoluteFile(), false);
            bw = new BufferedWriter(fw);
            bw.write(xmlContent);
            bw.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

记课时小程序说明 - 记上课小程序 - 全优学堂-培训机构管理系统全优学堂小程序消课,消课表,消课时小程序,免费记课时小程序,记课时小程序https://www.jljiayu.cn/2/6977642162435395584.html 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值