一、前言

因项目需求,小编要将项目从mysql迁移到oracle中 ~

之前已经完成 数据迁移 (https://zhengqing.blog.csdn.net/article/details/103694901)

现在将完成 基于MyBatis-Plus将项目中的MySQL语句全部转换Oracle语句

大概实现步骤:
  1. 将项目改成支持双库配置(因项目基于mysql数据库已经全部完成,也不想直接替换掉,于是新增oracle库,让整个项目可支持多个数据库,这里不是多数据源哦!)
  2. Oracle中创建常用函数
  3. 遍历项目中的xxxMapper.xml文件,找到mysql与oracle语句的区别,然后替换绝大部分SQL
  4. 最后将一些特殊的mysql语句手动修改为oracle语句

二、MyBatis-Plus 支持双库配置 【mysqloracle

1、application.yml中配置mybatis-plusdatabase-id

  1. # mybatis-plus配置
  2. mybatis-plus:
  3. configuration:
  4. jdbc-type-for-null: 'null' # 解决oracle更新数据为null时无法转换报错
  5. database-id: oracle # 支持多库配置 mysql,oracle

2、MybatisPlus核心配置文件 -> 根据不同的数据库厂商执行不同的SQL

  1. @Configuration
  2. @MapperScan("com.zhengqing.demo.modules.**.mapper*")
  3. public class MybatisPlusConfig {
  4. /**
  5. * `xxxMapper.xml`文件中的`databaseId`会自动识别使用的数据库类型与这里相对应
  6. * 注: 如果没有指定`databaseId`则该SQL语句适用于所有数据库哦~
  7. *
  8. * databaseIdProvider:支持多数据库厂商
  9. * VendorDatabaseIdProvider: 得到数据库厂商的标识(驱动getDatabaseProductName()),mybatis就能根据数据库厂商标识来执行不同的sql;
  10. * MySQL,Oracle,SQL Server,xxxx
  11. */
  12. @Bean
  13. public DatabaseIdProvider getDatabaseIdProvider(){
  14. DatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider();
  15. Properties properties = new Properties();
  16. // 为不同的数据库厂商起别名
  17. properties.setProperty("MySQL","mysql");
  18. properties.setProperty("Oracle","oracle");
  19. databaseIdProvider.setProperties(properties);
  20. return databaseIdProvider;
  21. }
  22. }

3、xxxMapper.xml中通过databaseId指定数据库类型

  1. <select id="selectUserInfo" resultMap="UserVO" databaseId="mysql">
  2. SELECT * FROM 表名 LIMIT 1
  3. </select>
  4. <select id="selectUserInfo" resultMap="UserVO" databaseId="oracle">
  5. SELECT * FROM 表名 WHERE ROWNUM &lt;= 1
  6. </select>

三、Oracle中创建常用函数

这里根据个人项目情况去实际应用即可~

1、ORACLE_TO_UNIX

Oracle时间 Date类型转换为Unix时间戳,等同于mysql中的UNIX_TIMESTAMP

  1. create or replace function ORACLE_TO_UNIX(in_date IN DATE) return number is
  2. begin
  3. return( ROUND( (in_date -TO_DATE('19700101','yyyymmdd'))*86400 - TO_NUMBER(SUBSTR(TZ_OFFSET(sessiontimezone),1,3))*3600, 0) );
  4. end ORACLE_TO_UNIX;

2、FIND_IN_SET

  1. CREATE OR REPLACE FUNCTION FIND_IN_SET(piv_str1 varchar2, piv_str2 varchar2, p_sep varchar2 := ',')
  2. RETURN NUMBER IS
  3. l_idx number:=0; -- 用于计算piv_str2中分隔符的位置
  4. str varchar2(500); -- 根据分隔符截取的子字符串
  5. piv_str varchar2(500) := piv_str2; -- piv_str2赋值给piv_str
  6. res number:=0; -- 返回结果
  7. loopIndex number:=0;
  8. BEGIN
  9. -- 如果piv_str中没有分割符,直接判断piv_str1piv_str是否相等,相等 res=1
  10. IF instr(piv_str, p_sep, 1) = 0 THEN
  11. IF piv_str = piv_str1 THEN
  12. res:= 1;
  13. END IF;
  14. ELSE
  15. -- 循环按分隔符截取piv_str
  16. LOOP
  17. l_idx := instr(piv_str,p_sep);
  18. loopIndex:=loopIndex+1;
  19. -- piv_str中还有分隔符时
  20. IF l_idx > 0 THEN
  21. -- 截取第一个分隔符前的字段str
  22. str:= substr(piv_str,1,l_idx-1);
  23. -- 判断 str piv_str1 是否相等,相等 res=1 并结束循环判断
  24. IF str = piv_str1 THEN
  25. res:= loopIndex;
  26. EXIT;
  27. END IF;
  28. piv_str := substr(piv_str,l_idx+length(p_sep));
  29. ELSE
  30. -- 当截取后的piv_str 中不存在分割符时,判断piv_strpiv_str1是否相等,相等 res=1
  31. IF piv_str = piv_str1 THEN
  32. res:= loopIndex;
  33. END IF;
  34. -- 无论最后是否相等,都跳出循环
  35. EXIT;
  36. END IF;
  37. END LOOP;
  38. -- 结束循环
  39. END IF;
  40. -- 返回res
  41. RETURN res;
  42. END FIND_IN_SET;

四、工具类(MySQL语句转换Oracle语句)

替换步骤:
  1. xxxMapper.xml 中将所有sql语句上加入 databaseId="mysql"
  2. 复制一份mysql的sql(即 将替换的oracle语句)
  3. 在复制的sql上加入databaseId="oracle"
  4. 找出mysql与oracle语句区别,然后替换sql

温馨小提示: 这里工具类只供参考,实际操作根据自己的项目做修改哦,操作前建议先备份自己的项目,以防操作不当丢失代码哦!

  1. import org.apache.commons.lang3.StringUtils;
  2. import org.junit.Test;
  3. import java.io.*;
  4. import java.util.*;
  5. /**
  6. * <p> mysql迁移oracle 测试工具类 </p>
  7. *
  8. * @description :
  9. * @author : zhengqing
  10. * @date : 2020/1/08 10:10
  11. */
  12. public class MySQLToOracleTest {
  13. private final static String ORACLE_SQL = " <!-- ====================================== ↓↓↓↓↓↓ oracle ↓↓↓↓↓↓ ====================================== -->";
  14. @Test // 替换项目中的sql语句
  15. public void testSQL() throws Exception {
  16. String path = System.getProperty("user.dir") + "\\src\\main\\java\\com\\zhengqing\\xxx"; // TODO 这里替换为自己的项目路径
  17. File file = new File(path);
  18. HashMap<Object, Object> fileMap = new HashMap<>();
  19. getAllFileByRecursion(fileMap, file);
  20. fileMap.forEach((key, value) -> {
  21. String fileXmlName = (String) key;
  22. File fileXml = (File) value;
  23. String filePath = fileXml.getPath();
  24. if (fileXmlName.equals("Test.xml")) {
  25. System.out.println(filePath);
  26. try {
  27. // 1、加入 databaseId="mysql"
  28. addMysql(filePath);
  29. // 2、复制一份oracle的sql
  30. if (!checkHasOracle(filePath)) {
  31. copyMysqlToOracle(filePath);
  32. }
  33. // 3、加入 databaseId="oracle"
  34. addOracle(filePath);
  35. // 4、替换mybatis `xxxMapper.xml` 中的sql语句
  36. repalceSQL(filePath);
  37. } catch (IOException e) {
  38. e.printStackTrace();
  39. }
  40. }
  41. });
  42. System.out.println(fileMap);
  43. }
  44. /**
  45. * 替换mybatis `xxxMapper.xml` 中的sql语句
  46. */
  47. private static void repalceSQL(String path) throws IOException {
  48. File file = new File(path);
  49. FileReader in = new FileReader(file);
  50. BufferedReader bufIn = new BufferedReader(in);
  51. // 内存流, 作为临时流
  52. CharArrayWriter tempStream = new CharArrayWriter();
  53. // 替换
  54. String line = null;
  55. int row = 0;
  56. int rowOracle = 0;
  57. while ((line = bufIn.readLine()) != null) {
  58. row++;
  59. if (line.contains(ORACLE_SQL)) {
  60. rowOracle = row;
  61. }
  62. if (rowOracle != 0 && row > rowOracle) {
  63. // ① 替换 `LIMIT` -> `AND ROWNUM &lt;= 1` TODO 【注: 部分包含`ORDER BY` 关键字,需单独处理】
  64. if (line.contains("limit") || line.contains("LIMIT")) {
  65. System.out.println();
  66. System.out.println(" ==============================↓↓↓↓↓↓ copy分页所需 (" + row + ") ↓↓↓↓↓↓===================================== ");
  67. System.out.println("SELECT * FROM ( SELECT TMP.*, ROWNUM ROW_ID FROM (");
  68. System.out.println();
  69. System.out.println(") TMP WHERE ROWNUM &lt;=1) WHERE ROW_ID > 0");
  70. System.out.println();
  71. }
  72. line = StringUtils.replace(line, "limit 1", "AND ROWNUM &lt;= 1");
  73. line = StringUtils.replace(line, "LIMIT 1", "AND ROWNUM &lt;= 1");
  74. line = StringUtils.replace(line, "limit 0,1", "AND ROWNUM &lt;= 1");
  75. line = StringUtils.replace(line, "LIMIT 0,1", "AND ROWNUM &lt;= 1");
  76. // ② oracle中不能使用“ ` ”符号
  77. line = StringUtils.replace(line, "`", "");
  78. // ③ CONCAT('%', #{name}, '%') -> '%'||#{name}||'%' (Oracle中concat函数只能放两个参数)
  79. if (line.contains("concat")) {
  80. // String newLine = line.substring(line.indexOf("concat(") + 7, line.lastIndexOf("'%')") + 3);
  81. line = line.replaceAll(",", " || ");
  82. line = line.replaceAll("concat", "");
  83. }
  84. if (line.contains("CONCAT")) {
  85. // String newLine = line.substring(line.indexOf("CONCAT(") + 7, line.lastIndexOf("'%')") + 3);
  86. line = line.replaceAll(",", " || ");
  87. line = line.replaceAll("CONCAT", "");
  88. }
  89. // ④ `UNIX_TIMESTAMP` -> `ORACLE_TO_UNIX` date类型时间转10位时间戳
  90. line = line.replaceAll("UNIX_TIMESTAMP", "ORACLE_TO_UNIX");
  91. // ⑤ 部分关键字需加上双引号 TODO 【注: 字段名大写,映射的别名需保存原本小写!】 `level -> "LEVEL"` `user -> "USER"` `number -> "NUMBER"` `desc -> "DESC"`
  92. List<String> keywordList = new ArrayList<>(Arrays.asList("level", "user", "number"));
  93. if (!line.contains("test=")) {
  94. for (String e : keywordList) {
  95. // StringUtils.swapCase(e) : 大小写互换
  96. line = line.replaceAll(" " + e + " ", " \"" + StringUtils.swapCase(e) + "\" ");
  97. line = line.replaceAll("." + e + " ", "\\.\"" + StringUtils.swapCase(e) + "\" ");
  98. if (line.endsWith(e) || line.endsWith(e + ",")) {
  99. line = line.replaceAll(e, "\"" + StringUtils.swapCase(e) + "\"");
  100. }
  101. }
  102. }
  103. if (line.endsWith(" date") || line.endsWith(" date,") || line.endsWith(" 'date'") || line.endsWith(" 'DATE'") || line.endsWith("DATE")) {
  104. line = line.replaceAll(" date", " \"date\"");
  105. line = line.replaceAll(" date,", " \"date,\"");
  106. line = line.replaceAll(" 'date'", " \"date\"");
  107. line = line.replaceAll(" 'DATE'", " \"date\"");
  108. line = line.replaceAll(" DATE", " \"date\"");
  109. }
  110. line = line.replaceAll(" date ", " \"date\" ");
  111. line = line.replaceAll(" DATE ", " \"date\" ");
  112. // ⑥ `IFNULL` -> `NVL`
  113. line = line.replaceAll("IFNULL", "NVL");
  114. line = line.replaceAll("ifnull", "NVL");
  115. // ⑦ 时间 `str_to_date` -> `to_date` `date_format` -> `to_char`
  116. // `%Y-%m-%d` -> `yyyy-MM-dd` `%Y-%m` -> `yyyy-MM`
  117. line = line.replaceAll("str_to_date", "TO_DATE");
  118. line = line.replaceAll("STR_TO_DATE", "TO_DATE");
  119. line = line.replaceAll("date_format", "TO_CHAR");
  120. line = line.replaceAll("DATE_FORMAT", "TO_CHAR");
  121. // 这里注意替换顺序问题,最长的应该放最前面!!!
  122. line = line.replaceAll("%Y-%m-%d %H:%i:%S", "yyyy-MM-dd HH24:mi:ss");
  123. line = line.replaceAll("%Y-%m-%d %H:%i:%s", "yyyy-MM-dd HH24:mi:ss");
  124. line = line.replaceAll("%Y-%m-%d %H:%i", "yyyy-MM-dd HH24:mi");
  125. line = line.replaceAll("%Y-%m-%d %H", "yyyy-MM-dd HH24");
  126. line = line.replaceAll("%Y-%m-%d %h", "yyyy-MM-dd HH");
  127. line = line.replaceAll("%Y-%m-%d", "yyyy-MM-dd");
  128. line = line.replaceAll("%Y-%m", "yyyy-MM");
  129. line = line.replaceAll("%Y", "yyyy");
  130. line = line.replaceAll("%H", "HH24");
  131. line = line.replaceAll("%k", "HH24");
  132. line = line.replaceAll("now\\(\\)", "(SELECT SYSDATE + 8/24 FROM DUAL)");
  133. line = line.replaceAll("NOW\\(\\)", "(SELECT SYSDATE + 8/24 FROM DUAL)");
  134. // ⑧ ...
  135. // 需手动处理的SQL 【 group by | 批量插入 | ... 】
  136. }
  137. // 将该行写入内存
  138. tempStream.write(line);
  139. // 添加换行符
  140. tempStream.append(System.getProperty("line.separator"));
  141. }
  142. // 关闭 输入流
  143. bufIn.close();
  144. // 将内存中的流 写入 文件
  145. FileWriter out = new FileWriter(file);
  146. tempStream.writeTo(out);
  147. out.close();
  148. }
  149. /**
  150. * 加入 databaseId="mysql"
  151. */
  152. private static void addMysql(String path) throws IOException {
  153. File file = new File(path);
  154. FileReader in = new FileReader(file);
  155. BufferedReader bufIn = new BufferedReader(in);
  156. // 内存流, 作为临时流
  157. CharArrayWriter tempStream = new CharArrayWriter();
  158. // 替换
  159. String line = null;
  160. while ((line = bufIn.readLine()) != null) {
  161. if ((line.contains("<select") || line.contains("<update") || line.contains("<insert") || line.contains("<delete")) && !line.contains("databaseId")) {
  162. if (line.endsWith(">")) {
  163. line = line.replaceAll(">", " databaseId=\"mysql\">");
  164. } else {
  165. line = line + " databaseId=\"mysql\"";
  166. }
  167. }
  168. // 将该行写入内存
  169. tempStream.write(line);
  170. // 添加换行符
  171. tempStream.append(System.getProperty("line.separator"));
  172. }
  173. // 关闭 输入流
  174. bufIn.close();
  175. // 将内存中的流 写入 文件
  176. FileWriter out = new FileWriter(file);
  177. tempStream.writeTo(out);
  178. out.close();
  179. }
  180. /**
  181. * 加入 databaseId="oracle"
  182. */
  183. private static void addOracle(String path) throws IOException {
  184. File file = new File(path);
  185. FileReader in = new FileReader(file);
  186. BufferedReader bufIn = new BufferedReader(in);
  187. // 内存流, 作为临时流
  188. CharArrayWriter tempStream = new CharArrayWriter();
  189. HashSet<String> lineSet = new HashSet<>();
  190. // 替换
  191. String line = null;
  192. while ((line = bufIn.readLine()) != null) {
  193. if (line.contains("databaseId=\"mysql\"")) {
  194. if (lineSet.contains(line)) {
  195. line = line.replaceAll("databaseId=\"mysql\"", "databaseId=\"oracle\"");
  196. }
  197. lineSet.add(line);
  198. }
  199. // 将该行写入内存
  200. tempStream.write(line);
  201. // 添加换行符
  202. tempStream.append(System.getProperty("line.separator"));
  203. }
  204. // 关闭 输入流
  205. bufIn.close();
  206. // 将内存中的流 写入 文件
  207. FileWriter out = new FileWriter(file);
  208. tempStream.writeTo(out);
  209. out.close();
  210. }
  211. /**
  212. * 复制一份oracle的sql
  213. */
  214. private static void copyMysqlToOracle(String path) throws IOException {
  215. File file = new File(path);
  216. FileReader in = new FileReader(file);
  217. BufferedReader bufIn = new BufferedReader(in);
  218. // 内存流, 作为临时流
  219. CharArrayWriter tempStream = new CharArrayWriter();
  220. // 替换
  221. String line = null;
  222. // 需要替换的行
  223. List<String> lineList = new LinkedList<>();
  224. int row = 0;
  225. int firstRow = 0;
  226. while ((line = bufIn.readLine()) != null) {
  227. row++;
  228. if (line.contains("<select") || line.contains("<update") || line.contains("<insert") || line.contains("<delete")) {
  229. firstRow = row;
  230. }
  231. // 添加替换内容
  232. if (firstRow != 0 && row >= firstRow && !line.contains("</mapper>")) {
  233. lineList.add(line);
  234. }
  235. // 查询结束位置
  236. if (line.contains("</mapper>")) {
  237. tempStream.append(System.getProperty("line.separator"));
  238. tempStream.write(ORACLE_SQL);
  239. tempStream.append(System.getProperty("line.separator"));
  240. tempStream.append(System.getProperty("line.separator"));
  241. lineList.forEach(lineValue -> {
  242. // copy mysql 语句 转为oracle
  243. try {
  244. tempStream.write(lineValue);
  245. tempStream.append(System.getProperty("line.separator"));
  246. } catch (IOException e) {
  247. e.printStackTrace();
  248. }
  249. });
  250. tempStream.append(System.getProperty("line.separator"));
  251. }
  252. // 将该行写入内存
  253. tempStream.write(line);
  254. // 添加换行符
  255. tempStream.append(System.getProperty("line.separator"));
  256. }
  257. // 关闭 输入流
  258. bufIn.close();
  259. // 将内存中的流 写入 文件
  260. FileWriter out = new FileWriter(file);
  261. tempStream.writeTo(out);
  262. out.close();
  263. }
  264. /**
  265. * 检查是否已经复制SQL
  266. */
  267. private static boolean checkHasOracle(String path) throws IOException {
  268. File file = new File(path);
  269. FileReader in = new FileReader(file);
  270. BufferedReader bufIn = new BufferedReader(in);
  271. // 内存流, 作为临时流
  272. CharArrayWriter tempStream = new CharArrayWriter();
  273. // 替换
  274. String line = null;
  275. boolean result = false;
  276. while ((line = bufIn.readLine()) != null) {
  277. if (line.contains(ORACLE_SQL)) {
  278. result = true;
  279. }
  280. // 将该行写入内存
  281. tempStream.write(line);
  282. // 添加换行符
  283. tempStream.append(System.getProperty("line.separator"));
  284. }
  285. // 关闭 输入流
  286. bufIn.close();
  287. // 将内存中的流 写入 文件
  288. FileWriter out = new FileWriter(file);
  289. tempStream.writeTo(out);
  290. out.close();
  291. return result;
  292. }
  293. /**
  294. * 递归文件夹 -> 找到所有xml文件
  295. */
  296. private static void getAllFileByRecursion(HashMap<Object, Object> fileMap, File file) {
  297. File[] fs = file.listFiles();
  298. for (File f : fs) {
  299. String fileName = f.getName();
  300. if (f.isDirectory()) {
  301. // 若是目录则递归,否则打印该目录下的文件
  302. getAllFileByRecursion(fileMap, f);
  303. }
  304. if (f.isFile() && fileName.endsWith(".xml")) {
  305. fileMap.put(fileName, f);
  306. }
  307. }
  308. }
  309. }

五、总结

这里简单说下MySQL和Oracle中的SQL区别,以及mysql语句转换oracle语句示例

1、分页

  1. mysql: LIMIT 0,1
  2. oracle: ROWNUM <= 1
情景①:mysql中不含ORDER BY
  1. -- mysql
  2. SELECT * FROM 表名 LIMIT 1
  3. -- oracle
  4. SELECT * FROM 表名 WHERE ROWNUM <= 1
情景②:mysql中含ORDER BY
  1. -- mysql
  2. SELECT * FROM 表名 ORDER BY 字段名 DESC LIMIT 1
  3. -- oracle
  4. SELECT * FROM (
  5. SELECT TMP.*, ROWNUM ROW_ID FROM (
  6. SELECT * FROM 表名 ORDER BY 字段名 DESC
  7. ) TMP WHERE ROWNUM <= 1 )
  8. WHERE ROW_ID > 0;
温馨小知识:SQL SELECT语句执行顺序
  1. FROM子句组装来自不同数据源的数据
  2. WHERE子句基于指定的条件对记录进行筛选
  3. GROUP BY子句将数据划分为多个分组
  4. 聚集函数进行计算
  5. HAVING子句筛选分组
  6. 计算所有表达式
  7. ORDER BY对结果进行排序

2、oracle中字段名不能使用符号 " ` " 包括

  1. -- mysql
  2. SELECT `字段名` FROM 表名
  3. -- oracle
  4. SELECT 字段名 FROM 表名

3、字符串拼接

注: Oracle中CONCAT函数只能放两个参数,因此改为 || 拼接

  1. mysql: CONCAT('%', 'xxx' , '%')
  2. oracle: '%' || 'xxx' || '%'
  1. -- mysql
  2. SELECT 字段名 FROM 表名 WHERE 字段名 LIKE CONCAT('%','helloworld','%')
  3. -- oracle
  4. SELECT 字段名 FROM 表名 WHERE 字段名 LIKE ('%' || 'helloworld' || '%')

4、date类型时间转10位时间戳

  1. mysql: UNIX_TIMESTAMP
  2. oracle: ORACLE_TO_UNIX (注:此函数为步骤三中手动创建的,并非oracle自带哦!)

5、字段名Oracle关键字需加上双引号

温馨小提示: 字段名需大写,如果Java实体类对应字段为小写,映射的别名注意需保持原本小写与之对应 ~

例如:

  1. level -> "LEVEL"
  2. user -> "USER"
  3. number -> "NUMBER"
  4. desc -> "DESC"
  5. date -> DATE

6、判断是否为 NULL: 如果x为NULL,则返回value,否则返回x值本身

  1. mysql: IFNULL(x, value)
  2. oracle: NVL(x, value)

7、日期时间互换

前mysql,后oracle

  1. 字符串类型转时间类型: STR_TO_DATE -> TO_DATE
  2. 时间类型转指定字符串类型: DATE_FORMAT -> TO_CHAR
  3. 获取系统当前时间: NOW() -> SELECT SYSDATE FROM DUAL
  1. -- 时间类型转指定字符串类型
  2. SELECT DATE_FORMAT( NOW(),'%Y-%m-%d %H:%i:%s'); -- mysql
  3. SELECT TO_CHAR( SYSDATE,'yyyy-MM-dd HH24:mi:ss') FROM DUAL; -- oracle
  4. -- 字符串类型转时间类型
  5. SELECT STR_TO_DATE( NOW(), '%Y-%m-%d %H'); -- mysql
  6. SELECT TO_DATE( '2020-01-09', 'yyyy-MM-dd') FROM DUAL; -- oracle 注:oracle中前者字符串时间的格式需与后者转换格式相同哦~
  7. -- 获取系统当前时间
  8. SELECT NOW(); -- mysql
  9. SELECT SYSDATE + 8/24 FROM DUAL; -- oralce 【注:如果服务器时间没有相差8小时则无需加上`8/24`
  10. -- mysql
  11. SELECT YEAR( NOW() ); -- 求年份
  12. SELECT QUARTER( NOW() ); -- 求季度
  13. SELECT MONTH( NOW() ); -- 求月份
  14. -- oracle
  15. SELECT TO_CHAR(SYSDATE, 'Q') FROM DUAL; -- 求季度

另外这里给出小编所用到的时间标识符格式

  1. -- 前:mysql 后:oracle
  2. "%Y-%m-%d %H:%i:%S" "yyyy-MM-dd HH24:mi:ss"
  3. "%Y-%m-%d %H:%i:%s" "yyyy-MM-dd HH24:mi:ss"
  4. "%Y-%m-%d %H:%i" "yyyy-MM-dd HH24:mi"
  5. "%Y-%m-%d %H" "yyyy-MM-dd HH24"
  6. "%Y-%m-%d %h" "yyyy-MM-dd HH"
  7. "%Y-%m-%d" "yyyy-MM-dd"
  8. "%Y-%m" "yyyy-MM"
  9. "%Y" "yyyy"
  10. "%H" "HH24"
  11. "%k" "HH24"

8、判断时 字段类型必须相同

这里注意是必须,可能在oracle版本不同的情况下,老版本不同类型也会查询出来,但建议还是改为相同类型关联,避免以后数据库版本升级出现问题!!!

建议小转大,比如:数字转字符串;并使用CONCAT去修改类型,因为mysql和oracle都支持此函数,并且不会在特殊类型上出现问题 ~

  1. -- ex: `JOIN` 关联表时 两张表的关联`字段类型`必须`相同`
  2. SELECT a.*,b.*
  3. FROM 1 a
  4. LEFT JOIN 2 b on a.字符串类型字段 = CONCAT(b.数字类型字段, '')

9、批量插入

  1. -- mysql
  2. <insert id="insertBatch" databaseId="mysql">
  3. INSERT INTO 表名( `字段名1`, `字段名2`, `字段...`) VALUES
  4. <foreach collection="list" item="item" separator="," open="(" close=")">
  5. #{item.字段1},#{item.字段2},#{item中的每一个字段名...}
  6. </foreach>
  7. </insert>
  8. -- oracle
  9. <insert id="insertBatch" databaseId="oracle">
  10. INSERT INTO 表名(字段名1,字段名2,xxx...)
  11. SELECT A.*
  12. FROM(
  13. <foreach collection="list" item="item" index="index" separator="UNION ALL" >
  14. SELECT
  15. #{item.字段1},#{item.字段2},#{item中的每一个字段名...}
  16. FROM DUAL
  17. </foreach>
  18. ) A
  19. </insert>

10、分组 GROUP BY

oracle中GROUP BY分组后,查询出来的所有字段(除分组字段)必须为聚合函数的字段,否则会报错!

解决:

  1. 查询字段改为聚合函数
  2. 使用如下分析函数 OVER (Partition BY ...) 及开窗函数
  1. -- mysql
  2. SELECT 字段名,xxx... FROM 表名 GROUP BY 分组字段
  3. -- oracle
  4. SELECT
  5. *
  6. FROM (
  7. SELECT tb.*, ROW_NUMBER ( ) OVER ( PARTITION BY tb.分组字段 ORDER BY tb.排序字段 DESC ) AS result
  8. FROM (
  9. SELECT 字段名,xxx... FROM 表名 -- 此处为查询sql,去掉`GROUP BY`分组条件,将分组字段加到上面 注:此sql的查询字段中要么全是聚合函数字段,要么都不是!
  10. ) tb
  11. ) WHERE result = 1

11、Oracle中表的别名不能用AS, 列的别名可以用AS

why ?:为了防止和Oracle存储过程中的关键字AS冲突的问题

12、注意Oracle对数据类型要求很严!!!

MySQL与Oracle不同之处远不止小编提及的如上几点,更多的还需要大家根据在实际项目中做对比,然后去修改哦 ~

六、本文MySQL转Oracle语句工具源码

温馨小提示:如果后期小编空闲会将上文中提供的测试替换工具类再加以修改,到时候会存放在如下github仓库中...

https://github.com/zhengqingya/mysql-to-oracle

MyBatis项目实战 快速将MySQL转换成Oracle语句的更多相关文章

  1. springBoot 整合 mybatis 项目实战

    二.springBoot 整合 mybatis 项目实战   前言 上一篇文章开始了我们的springboot序篇,我们配置了mysql数据库,但是我们sql语句直接写在controller中并且使用 ...

  2. 使用navicat将mysql转换成sqlserver

    使用navicat将mysql转换成sqlserver 1. 打开navicat,连接所需要装换的mysql数据库. 2. 选择所需要转换的数据源,点击右键选择数据传输.如图: 3. 打开数据传输面板 ...

  3. 将json文件转换成insert语句的sql文件

    引入是要的maven依赖: <!-- https://mvnrepository.com/artifact/com.google.code.gson/gson --> <depend ...

  4. excel转换成oracle建表脚本

    package excel2sql; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundE ...

  5. 【springmvc+mybatis项目实战】杰信商贸-7.生产厂家新增

    我们要实现新的功能,就是生产厂家的新增先来回顾一下系统架构图我们数据库这边已经建好表了,接下来要做的就是mapper映射 编辑FactoryMapper.xml文件,加入“添加”的逻辑配置代码块 &l ...

  6. 【springmvc+mybatis项目实战】杰信商贸-5.生产厂家DAO+SERVICE+CONTROLLER+JSP+配置文件

    上一篇我们创建了工程和一个Factory的po对象(javaBean),我们也写好了Mapper的映射文件,接下来我们来完成生产厂家的DAO与SERVICE,以及CONTROLLER,还有做显示的JS ...

  7. 【springmvc+mybatis项目实战】杰信商贸-1.项目背景

    1.项目背景杰信项目物流行业的项目,杰信商贸是国际物流行业一家专门从事进出口玻璃器皿贸易的公司.公司总部位于十一个朝代的帝王之都西安,业务遍及欧美.随着公司不断发展壮大,旧的信息系统已无法满足公司的快 ...

  8. 二、springBoot 整合 mybatis 项目实战

    前言 上一篇文章开始了我们的springboot序篇,我们配置了mysql数据库,但是我们sql语句直接写在controller中并且使用的是jdbcTemplate.项目中肯定不会这样使用,上篇文章 ...

  9. 【springmvc+mybatis项目实战】杰信商贸-2.数据库配置

    首先我们来了解项目的架构 我们分别使用了MySql和Oracle数据库,即是异构数据库.我们做到一个平台支持多个数据库.数据库建模我们使用Sybase公司的PowerDesigner(以后简称PD), ...

随机推荐

  1. Android Studio(二):快捷键设置、插件安装

    Android Studio相关博客: Android Studio(一):介绍.安装.配置 Android Studio(二):快捷键设置.插件安装 Android Studio(三):设置Andr ...

  2. H3C 数据封装与解封装

  3. Argus--[优先队列]

    Description A data stream is a real-time, continuous, ordered sequence of items. Some examples inclu ...

  4. 如何通过命令行 msbuild 编译项目

    本文告诉大家如何通过 msbuild 编译一个项目,通过命令行编译可以输出更多的编译信息,可以用来调试自己写的编译相关方法,可以看到是哪个文件编译失败 在开始菜单可以找到 VisualStudio 的 ...

  5. linux strace 命令

    有时小问题可以通过观察用户空间的应用程序的行为来追踪. 监视程序也有助于建立对驱 动正确工作的信心. 例如, 我们能够对 scull 感到有信心, 在看了它的读实现如何响应 不同数量数据的读请求之后. ...

  6. [学习笔记]Pollard-Rho

    之前学的都是假的 %%zzt Miller_Rabin:Miller-Rabin与二次探测 大质数分解: 找到所有质因子,再logn搞出质因子的次数 方法:不断找到一个约数d,递归d,n/d进行分解, ...

  7. linux 一次对一个用户限制存取

    单打开设备之外的下一步是使一个用户在多个进程中打开一个设备, 但是一次只允许一个 用户打开设备. 这个解决方案使得容易测试设备, 因为用户一次可从几个进程读写, 但是 假定这个用户负责维护在多次存取中 ...

  8. 从物联网设备生命周期理解Apple Homekit框架

    本次笔记主要基于苹果公开的HomeKit Accessory Protocol协议文档和IOS Security Guide中相关部分. 总体来讲,设备与App之间采用端到端的加密,密钥由设备和App ...

  9. 如何在MPlayer上支持RTSP

    http://www.live555.com/mplayer/ 请按照如下步骤 下载 "LIVE555 Streaming Media" l的库的源码, 解压后 将"li ...

  10. 用ubuntu里的vim搭建一个apache2+php+mysql环境一路踩的坑

    先是安装apache2,这个很顺利,一个apt install apache就搞定了. (PS:查看linux是否已经安装了apache服务,可以通过执行apachectl -v,如果安装了的话会显示 ...