oracle轉(zhuǎn)mysql語句轉(zhuǎn)換實例代碼
場景:Oracle數(shù)據(jù)庫 -> TD數(shù)據(jù)庫(騰訊),而TD數(shù)據(jù)庫實質(zhì)上是對mysql數(shù)據(jù)庫的封裝拓展。因此,需要對項目中oracle的sql進(jìn)行適配性轉(zhuǎn)化,即在sql查詢結(jié)果不變的前提下,轉(zhuǎn)換成符合mysql語法的sql語句。
tips:其實TD數(shù)據(jù)庫8.0以上版本的語法大部分是可以完美兼容oracle語法的。但是我們的版本是5.7,因此許多函數(shù)和語法是不兼容oracle。如果你的td數(shù)據(jù)庫版本在8以上,就不用往下看了。
一、oracle函數(shù) -> mysql函數(shù)
1. decode -> case when
-- oracle: decode select decode(1, 1, 'out1', 2, 'out2') from dual; -- out1 select decode(2, 1, 'out1', 2, 'out2') from dual; -- out2 select decode(3, 1, 'out1', 2, 'out2') from dual; -- null --mysql: 1. case [col_name] when select case 1 when 1 then 'out1' when 2 then 'out2' end; -- out1 select case 2 when 1 then 'out1' when 2 then 'out2' end; -- out2 select case 3 when 1 then 'out1' when 2 then 'out2' end; -- null -- mysql: 2. case when [expr] select case when 1 > 0 then 'out0' end; -- out0 1和2的區(qū)別在于,1中case后只能跟列,而2中case when后是可以跟表達(dá)式的,適合復(fù)雜情況
2. NVL(exp1,exp2) -> ifnull
-- oracle: nvl(param, val) select nvl(null, 1) from dual; -- 1 select nvl('', 1) from dual; -- 1 select nvl('0', 1) from dual; -- 0 -- mysql: ifnull(param, val) select ifnull(null,1);-- 1 select ifnull('',1); -- '' select ifnull('0',1); -- 0 nvl中null和''都輸出1,是因為oracle中,空值''即為null select '' from dual; -- null 而ifnull中''輸出'',是與oracle不同的,因此在進(jìn)行函數(shù)替換的時候,要注意, 如果條件值不為''時,才與nvl等價。如數(shù)字類型不會為'' 如果param可能為''時,需要用case when等價替換,例如: select case param when '' then 'empty' when null then 'nul' else 'val end';
3. NVL2(exp1,exp2,exp3) -> if(expr1,expr2,expr3)
-- oracle nvl2(exp1,exp2,exp3) select nvl2(1, '123', 'null') from dual; -- 123 select nvl2('', '123', 'null') from dual; -- null select nvl2(null, '123', 'null') from dual; -- null --mysql if(param,notNullVal,nullVal) select if(1, 123, 'null');-- 123 select if('', 123, 'null');-- null select if(null, 123, 'null');-- null 此時看起來是等同的,那就大錯特錯了。 接下來看數(shù)據(jù)庫實際情況: -- oacle: int_col_0 是int類型 值為0 select nvl2(int_col_0, 123, null) from demo where id = '1'; -- 123 -- mysql: int_col_0 是int類型 值為0 select if(int_col_0, 123, null) from demo where id = '1'; -- null 這時候兩個函數(shù)的結(jié)果就不一樣了。 原因如下:if(param,notNullVal,nullVal)函數(shù)中,如果param是varchar類型,當(dāng)param 值為''時,會輸出后值;如果param時int類型,當(dāng)param值為0時,會輸出后值;當(dāng)param是 decimal類型,當(dāng)param為0.0時,會輸出后者。 得出結(jié)論:當(dāng)param的值為其數(shù)據(jù)類型的默認(rèn)值時,if()函數(shù)會走后者。 因此,在param數(shù)據(jù)類型為varchar時,與nvl2函數(shù)是等價的。
4. TO_NUMBER(exp) -> CAST(value AS datatype)
-- 這個沒什么講的,可以直接用,在mysql中cast函數(shù)用于將數(shù)據(jù)類型強(qiáng)轉(zhuǎn)為其它數(shù)據(jù)類型 類似于java。 select CAST('123' AS decimal(5,1) ); -- 123.0
5. to_char
a. to_char(date, dateFormatType) -> date_format(date, dateFormatType)
-- oracle: to_char(date, dateFormatType) select to_char(sysdate, 'yyyymmdd') from dual; -- 20230222 -- mysql: date_format(date, dateFormatType) select date_format(now(), '%Y%m%d'); -- 20230222
b. to_char(str) -> CAST(value AS char)
-- oracle to_char select to_char(sysdate) from dual; -- [varchar2] 22-2月 -23 --mysql: cast(value AS char) select cast(now() as char ); -- [varcahr]2023-02-22 09:10:02
6. TRUNC() -> DATE()
-- oracle trunc() SELECT TRUNC(sysdate) from DUAL; -- [DATE]2023-02-21 00:00:00 SELECT TRUNC(to_date('20210101','yyyymmdd')) from DUAL; -- [DATE]2021-01-01 00:00:00 -- mysql date() SELECT DATE(NOW()); -- [DATE]2023-02-21 SELECT DATE('20210201'); -- [DATE]2021-02-01
7. to_date -> str_to_date
-- oracle: to_date select to_date('20210101', 'yyyymmdd') from dual; -- 2021-01-01 00:00:00 -- mysql : str_to_date select str_to_date('20210101', '%Y%m%d'); -- 2021-01-01
8. 常用時間格式轉(zhuǎn)換
oracle -> mysql YYYYmmdd -> %Y%m%d YYYY-mm-dd -> %Y-%m-%d yyyy-mm-dd hh24:mi:ss -> %Y-%m-%d %H:%i:%s
9. 時間計算方式
a. 日期+/-1天
-- oracle select to_date('20210101', 'yyyymmdd') - 1 from dual; -- 2020-12-31 00:00:00 -- mysql select str_to_date('20210101', '%Y%m%d') - 1 from dual; -- 20210100 從結(jié)果可以看出是錯誤的,只是單純-1,并沒有校驗時間是否正確。 -- mysql adddate(date, [num]) select adddate(str_to_date('20210101', '%Y%m%d'), -1); -- 2020-12-31 -- mysql date_sub/date_add(date, interval [num] [day/month/year...]) select date_sub(str_to_date('20210101', '%Y%m%d'), interval 1 day ); -- 2020-12-31 select date_add(str_to_date('20210101', '%Y%m%d'), interval 1 day ); -- 2021-01-02 其中interval后可跟如下時間單位: FRAC_SECOND SECOND MINUTE HOUR DAY WEEK MONTH QUARTER YEAR
b. 日期+/-1月/年
-- oracle add_months(date, num) select add_months(to_date('20210101','yyyymmdd'), 1) from dual; -- 2021-02-01 00:00:00 -- mysql date_add(date,, interval [num] month) select date_add(str_to_date('20210101', '%Y%m%d'), interval 1 month ); --2021-02-01 -- mysql SELECT TIMESTAMPADD(SQL_TSI_MONTH, 1, str_to_date('20210101', '%Y%m%d')); -- 2021-02-01 tips: mybatis中使用date_add時,一旦里賣弄interval關(guān)鍵字,總是會sql編譯失敗, 不知道是否和版本還是什么有關(guān)。 使用TIMESTAMPADD函數(shù)不會報錯。 interval-type間隔類型參數(shù)如下: SQL_TSI_FRAC_SECOND SQL_TSI_SECOND SQL_TSI_MINUTE SQL_TSI_HOUR SQL_TSI_DAY SQL_TSI_WEEK SQL_TSI_MONTH SQL_TSI_QUARTER SQL_TSI_YEAR
10. SUBSTR() -> SUBSTRING()
-- 截取字符串: 注意: -- oracle select SUBSTR('123456', 1, 3)、SUBSTR('123456', 0, 3) from dual; -- 輸出都是123; -- mysql select SUBSTRING('123456', 1, 3); -- 輸出123 select SUBSTRING('123456', 0, 3); --輸出空值''
11. 拼接符號|| -> concat(str, str1)
-- mysql concat(str1,str2,...) select concat('1','2','3','4','A'); -- 1234A
12. length() -> char_length()
-- oracle length() select char_length(''); -- null select LENGTH('123'), '123' from dual; -- 3 select LENGTH(0.00), 0.00 from dual; -- 1 select LENGTH(0), 0 from dual; -- 1 select LENGTH(0.000001), 123456 from dual; -- 7 select LENGTH(sysdate), sysdate from dual; -- 9 2023-02-22 01:23:39 -- mysql char_length select char_length(''); -- 0 select char_length(123); -- 3 select char_length(0); -- 1 select char_length(0.0); -- 3 select char_length(0.000001); -- 8 select char_length(now()), now(); -- 19 2023-02-22 09:18:34 tips: 可以看出,oracle的length()對于字符串的長度計算結(jié)果是符合我們預(yù)期的,但是數(shù)字類型和并不會把 小數(shù)點的長度加上。且當(dāng)為0.0000時,會自動轉(zhuǎn)會為0再做長度計算,得出結(jié)果為1.時間格式 時摻長度我也不確定是怎么得出的。 mysql的char_length()結(jié)果就比較符合我們的期望。會把所有參數(shù)都轉(zhuǎn)化為char類型后,再進(jìn)行 長度計算。 注意:當(dāng)字符串計算長度時,如果字符串為空'',oracle-length()的結(jié)果為null,mysql- char_length的結(jié)果為0。
二、oracle語法 -> mysql語法
有些語法也不是通用的,下面是經(jīng)常見到的幾種。
1. 臨時表with as
解決方案1:換成子查詢放到表調(diào)用處
解決方案2:在java中拆分,減少sql復(fù)雜度。
2. 左右連接(+)寫法
解決方案:根據(jù)原sql where后的表連接條件,有(+)的換成left join,沒有的換成inner join
3. 遞歸 connect by prior
解決方案:這塊內(nèi)容比較多,另開了一篇:[‘@實現(xiàn)mysql遞歸查詢’]
4. merge語法
解決方案:sql拆成查詢、更新、插入三個語句。在java中組合調(diào)用
總結(jié)
到此這篇關(guān)于oracle轉(zhuǎn)mysql語句轉(zhuǎn)換的文章就介紹到這了,更多相關(guān)oracle轉(zhuǎn)mysql語句內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Oracle查看正在執(zhí)行的sql語句的方法大全
- oracle數(shù)據(jù)庫查看鎖表的sql語句整理
- Oracle中sql語句如何執(zhí)行日志查詢
- Oracle如何在SQL語句中對時間操作、運算
- oracle數(shù)據(jù)庫導(dǎo)入.dmp腳本的sql 語句
- ORACLE中如何找到未提交事務(wù)的SQL語句詳解
- SELECT INTO 和 INSERT INTO SELECT 兩種表復(fù)制語句詳解(SQL數(shù)據(jù)庫和Oracle數(shù)據(jù)庫的區(qū)別)
- Oracle數(shù)據(jù)庫找到 Top Hard Parsing SQL 語句的方法
相關(guān)文章
MySQL 存儲過程傳參數(shù)實現(xiàn)where id in(1,2,3,...)示例
一個MySQL 存儲過程傳參數(shù)的問題想實現(xiàn)例如篩選條件為:where id in(1,2,3,...),下面有個不錯的示例,感興趣的朋友可以參考下2013-10-10mysql 5.7.17 免安裝版配置方法圖文教程(windows10)
這篇文章主要為大家詳細(xì)介紹了windows10下mysql 5.7.17 免安裝版配置方法圖文教程,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-01-01SQL實現(xiàn)LeetCode(176.第二高薪水)
這篇文章主要介紹了SQL實現(xiàn)LeetCode(176.第二高薪水),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08生產(chǎn)庫自動化MySQL5.6安裝部署詳細(xì)教程
自動化運維是一個DBA應(yīng)該掌握的技術(shù),其中,自動化安裝數(shù)據(jù)庫是一項基本的技能,這篇文章主要介紹了生產(chǎn)庫自動化MySQL5.6安裝部署詳細(xì)教程,需要的朋友可以參考下2016-09-09