oracle的sql轉換爲mysql的sql語法問題記錄.續

背景

oracle的sql轉換爲mysql的sql語法問題記錄

問題

oracle寫法:

SELECT ? AS id,
REGEXP_SUBSTR (?, '[^,]+', 1,rownum) n0,
REGEXP_SUBSTR (?, '[^,]+', 1,rownum) n1,
... 中間省略一堆
REGEXP_SUBSTR (?, '[^,]+', 1,rownum) nn
from dual connect by rownum<=LENGTH (?) - LENGTH (regexp_replace(?, ',', ''))+1

說明:

先對用到的函數一一釋義,

1. REGEXP_SUBSTR:  官方文檔的截圖

REGEXP_SUBSTR通過允許在字符串中搜索正則表達式模式來擴展SUBSTR函數的功能,不過它返回的不是子字符串的位置,而是子字符串本身。

source_char是用作搜索值的字符表達式

pattern是正則表達式

position是一個正整數,指示Oracle應該在其中開始搜索的source_char字符。默認值爲1,表示Oraclesource_char的第一個字符開始搜索

occurrence是一個正整數,指示Oracle應該在source_char中搜索哪個模式出現。缺省值爲1,表示Oracle搜索第一次出現的模式

match_parameter是文本字面值,可讓您更改函數的默認匹配行爲

對於具有子表達式的模式,subexpr是從09的非負整數,指示該函數將返回模式中的哪個子表達式

先忽略connect by的部分,假定rownum是1:Select REGEXP_SUBSTR (?, '[^,]+', 1,rownum) from dual,也假定?變量的值是字符串aa,bb,cc.

可以看做, Select REGEXP_SUBSTR (‘aa,bb,cc’, '[^,]+', 1,1) from dual的意思是將’aa,bb,cc’,以逗號分隔取第一個,即aa.

實際我的業務場景遇到一個問題:

這裏用的?變量,這個?在這裏出現一次,意味’aa,bb,cc’,做爲參數只能出現一次,我轉換爲mysql時也只能出現一次。

所以,需要避免’aa,bb,cc’會作爲2次參數使用的實現方式。

不要問爲什麼,當前這個?號不能用兩次。所以如果是連續逗號去重也很麻煩,做爲參數只能出現一次,那就不好處理。oracle好歹有這個正則拆分,一次處理好。

根據我推測當前上下文場景,排除掉了出現連續逗號的情況,所以轉mysql實際看做一個逗號處理。

mysql替代方案:

使用SUBSTRING_INDEX(str,delim,count)

在出現定界符delim之前,從字符串str返回子字符串。count是我要的那個1

2. oralce : length(str),返回字符串長度

此處理論上不能使用mysql的length,oracle的length使用字符來定義長度,而mysql的length是以字節爲單位的,

比如字符串’abcde‘,兩個都返回5,但如果是字符串’abcde中國人’,有3個漢字,看效果:

Oracle還是8:

Mysql是14:

mysql替代方案:CHAR_LENGTH(str)/ CHARACTER_LENGTH(str)返回字符串str的長度,以字符爲單位

3. oracle: regexp_replace(src, pat, dst), 將字符串src中的pat,替換爲dst

把逗號去掉

mysql替代方案:

當前場景使用:REPLACE(str,from_str,to_str)即可。返回字符串str,其中所有出現的字符串from_str都替換爲字符串to_str

4. 最後一部分:connect by rownum<=

不多說,看結果 吧,只查dual,rownum是1:

但是這裏要查一個數字序列,想遞歸查詢:

所以上面整個sql的目的就是:將字符串以逗號進行拆分,轉換爲行。如下:

mysql最終解決方案:

SELECT
	SUBSTRING_INDEX(
		SUBSTRING_INDEX('aa,bb,cc', ',', rownum),
		',',
		- 1
	)
FROM
	(
		SELECT
			@rownum :=@rownum + 1 AS rownum,
			TABLE_NAME
		FROM
			information_schema. PARTITIONS,
			(SELECT @rownum := 0) t
		WHERE
			DATABASE () = TABLE_SCHEMA
	) t
WHERE
	rownum <= CHAR_LENGTH('aa,bb,cc') - CHAR_LENGTH(REPLACE('aa,bb,cc', ',', '')) + 1;

說明下:

對於其中用到的幾個函數,前面都已經說明了。這個@rownum是我定義的變量。對於:

    SUBSTRING_INDEX(
        SUBSTRING_INDEX('aa,bb,cc', ',', rownum),
        ',',
        - 1
    )

這部分,是通過rownum遞增,分別取出aa,bb,cc。內層的: SUBSTRING_INDEX('aa,bb,cc', ',', rownum),隨着rownum遞增,分別返回aa\aa,bb\,aa,bb,cc,外層的參數-1,就是分別返回aa,bb,cc了。

rownum <= CHAR_LENGTH('aa,bb,cc') - CHAR_LENGTH(REPLACE('aa,bb,cc', ',', '')) + 1;這部分返回rownum的限制大小,就是aa,bb,cc能分成幾部分。

from-where中間的嵌套子查詢和變量定義,其實返回的是當前數據庫中所有表的表名和它的行號,它的行號就是rownum的值。這種實現只對我當前場景百分百準確有用。因爲aa,bb,cc實際在當前場景是數據庫的表名組成的,所以它拆分的個數一定不會超過當前數據庫表的總量。如果不是我這種場景,無法確定拆分字符串的時候能拆出來多少,這個rownum可能就要足夠大,至少要比其中的分隔符要多吧,就需要考慮其它實現方案,比較藉助輔助表及輔助字段等手段。

oracle寫法:哎,這場景。 一條一二百行的sql,要改動的點不少,還有一堆變量,不說了,只補充點前面沒提示到的吧。

1)Case when不用改,oracle基本和mysql差不多。

2)substr(str, instr(str,?), length(?)) = ?,,,用來判斷str裏是否包子字符串

substr: SUBSTR函數返回char的一部分,從char位置開始,substring_length個字符長。 SUBSTR使用輸入字符集定義的字符來計算長度。 SUBSTRB使用字節而不是字符。 SUBSTRC使用Unicode完整字符。 SUBSTR2使用UCS2代碼點。 SUBSTR4使用UCS4代碼點.

mysql替代方案:

substr可以使用Mysql的:SUBSTR()/SUBSTRING().

所以不用改了

3)to_char(to_date(to_char(begintime,'yyyy-mm-dd'),'yyyy-mm-dd')+7,'yyyy-mm-dd') >= to_char(to_date(to_char(process_time,'yyyy-mm-dd'),'yyyy-mm-dd'),'yyyy-mm-dd')

不就判斷兩個日期是否相差7天,最後還用字符串字典排序比較,真tm費勁.

Mysql替代方案:

DATE_ADD/ ADDDATE

DATE_FORMAT(DATE_ADD(begintime,INTERVAL 7 DAY),'%Y-%m-%d') >= DATE_FORMAT(process_time,'%Y-%m-%d ')

oracle寫法:add_months

ADD_MONTHS返回一個加上加上整數月的日期

mysql替代方案:DATE_ADD/ ADDDATE

這裏的sysdate就用now()代替了,畢竟當前場景需要使用now()了。

oracle寫法:MOD

求餘

Mysql: MOD(N,M)N % MN MOD M都可以,這裏就不用改了

oracle寫法:最後一個

oracle創建表的時候:其中有個字段

create table t_demo(
    day              NUMBER(2) default to_char(SYSDATE, 'dd')
)

默認值 是當月的第幾天,需要調用函數 。Mysql默認值 是不能調用函數的。

mysql替代方案:創建觸發器

-- 創建 表t_demo 的觸發器
CREATE TRIGGER t_demo BEFORE INSERT ON t_demo FOR EACH ROW
BEGIN

IF NEW.day IS NULL THEN

SET NEW.day = DATE_FORMAT(now(), '%d');

END
IF;
END;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章