oracle轉(zhuǎn)mysql語句轉(zhuǎn)換實(shí)例代碼
場(chǎng)景:Oracle數(shù)據(jù)庫 -> TD數(shù)據(jù)庫(騰訊),而TD數(shù)據(jù)庫實(shí)質(zhì)上是對(duì)mysql數(shù)據(jù)庫的封裝拓展。因此,需要對(duì)項(xiàng)目中oracle的sql進(jìn)行適配性轉(zhuǎn)化,即在sql查詢結(jié)果不變的前提下,轉(zhuǎn)換成符合mysql語法的sql語句。
tips:其實(shí)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,是因?yàn)閛racle中,空值''即為null
select '' from dual; -- null
而ifnull中''輸出'',是與oracle不同的,因此在進(jìn)行函數(shù)替換的時(shí)候,要注意,
如果條件值不為''時(shí),才與nvl等價(jià)。如數(shù)字類型不會(huì)為''
如果param可能為''時(shí),需要用case when等價(jià)替換,例如:
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í)看起來是等同的,那就大錯(cuò)特錯(cuò)了。
接下來看數(shù)據(jù)庫實(shí)際情況:
-- 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í)候兩個(gè)函數(shù)的結(jié)果就不一樣了。
原因如下:if(param,notNullVal,nullVal)函數(shù)中,如果param是varchar類型,當(dāng)param
值為''時(shí),會(huì)輸出后值;如果param時(shí)int類型,當(dāng)param值為0時(shí),會(huì)輸出后值;當(dāng)param是
decimal類型,當(dāng)param為0.0時(shí),會(huì)輸出后者。
得出結(jié)論:當(dāng)param的值為其數(shù)據(jù)類型的默認(rèn)值時(shí),if()函數(shù)會(huì)走后者。
因此,在param數(shù)據(jù)類型為varchar時(shí),與nvl2函數(shù)是等價(jià)的。4. TO_NUMBER(exp) -> CAST(value AS datatype)
-- 這個(gè)沒什么講的,可以直接用,在mysql中cast函數(shù)用于將數(shù)據(jù)類型強(qiáng)轉(zhuǎn)為其它數(shù)據(jù)類型
類似于java。
select CAST('123' AS decimal(5,1) ); -- 123.05. 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-017. 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-018. 常用時(shí)間格式轉(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. 時(shí)間計(jì)算方式
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é)果可以看出是錯(cuò)誤的,只是單純-1,并沒有校驗(yàn)時(shí)間是否正確。
-- 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后可跟如下時(shí)間單位:
FRAC_SECOND
SECOND
MINUTE
HOUR
DAY
WEEK
MONTH
QUARTER
YEARb. 日期+/-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時(shí),一旦里賣弄interval關(guān)鍵字,總是會(huì)sql編譯失敗,
不知道是否和版本還是什么有關(guān)。
使用TIMESTAMPADD函數(shù)不會(huì)報(bào)錯(cuò)。
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_YEAR10. 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. 拼接符號(hào)|| -> concat(str, str1)
-- mysql concat(str1,str2,...)
select concat('1','2','3','4','A'); -- 1234A12. 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()對(duì)于字符串的長(zhǎng)度計(jì)算結(jié)果是符合我們預(yù)期的,但是數(shù)字類型和并不會(huì)把
小數(shù)點(diǎn)的長(zhǎng)度加上。且當(dāng)為0.0000時(shí),會(huì)自動(dòng)轉(zhuǎn)會(huì)為0再做長(zhǎng)度計(jì)算,得出結(jié)果為1.時(shí)間格式
時(shí)摻長(zhǎng)度我也不確定是怎么得出的。
mysql的char_length()結(jié)果就比較符合我們的期望。會(huì)把所有參數(shù)都轉(zhuǎn)化為char類型后,再進(jìn)行
長(zhǎng)度計(jì)算。
注意:當(dāng)字符串計(jì)算長(zhǎng)度時(shí),如果字符串為空'',oracle-length()的結(jié)果為null,mysql-
char_length的結(jié)果為0。二、oracle語法 -> mysql語法
有些語法也不是通用的,下面是經(jīng)常見到的幾種。
1. 臨時(shí)表with as
解決方案1:換成子查詢放到表調(diào)用處
解決方案2:在java中拆分,減少sql復(fù)雜度。
2. 左右連接(+)寫法
解決方案:根據(jù)原sql where后的表連接條件,有(+)的換成left join,沒有的換成inner join
3. 遞歸 connect by prior
解決方案:這塊內(nèi)容比較多,另開了一篇:[‘@實(shí)現(xiàn)mysql遞歸查詢’]
4. merge語法
解決方案:sql拆成查詢、更新、插入三個(gè)語句。在java中組合調(diào)用
總結(jié)
到此這篇關(guān)于oracle轉(zhuǎn)mysql語句轉(zhuǎn)換的文章就介紹到這了,更多相關(guān)oracle轉(zhuǎn)mysql語句內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Oracle查看正在執(zhí)行的sql語句的方法大全
- oracle數(shù)據(jù)庫查看鎖表的sql語句整理
- Oracle中sql語句如何執(zhí)行日志查詢
- Oracle如何在SQL語句中對(duì)時(shí)間操作、運(yùn)算
- 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中查詢?nèi)罩九c慢查詢?nèi)罩镜幕緦W(xué)習(xí)教程
這篇文章主要介紹了MySQL中查詢?nèi)罩九c慢查詢?nèi)罩镜幕緦W(xué)習(xí)教程,文中還提到了MySQL自帶的Mysqldumpslow日志分析工具的使用,需要的朋友可以參考下2015-12-12
使用Canal和Kafka解決MySQL與緩存的數(shù)據(jù)一致性問題
這篇文章主要介紹了使用Canal和Kafka解決MySQL與緩存的數(shù)據(jù)一致性問題,文中通過圖文結(jié)合的方式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-07-07
MySQL的存儲(chǔ)函數(shù)與存儲(chǔ)過程的區(qū)別解析
這篇文章主要介紹了MySQL的存儲(chǔ)函數(shù)與存儲(chǔ)過程的區(qū)別,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-04-04
MySQL中使用PROFILING來查看SQL執(zhí)行流程的實(shí)現(xiàn)步驟

