Mysql我是怎麼隨機擷取字元數組裡的字串並且一一對應
場景:臨近年底,各個App都會有個人年度賬單,專案裡為了圖快,以及節省各個系統模組之間的介面聯調。直接人工統計資料(:flushed::flushed::flushed::flushed::flushed::flushed::flushed::flushed::flushed::flushed::flushed::flushed::flushed::flushed:),構造賬單資料JSON。
話不多說,老夫拿起鍵盤就是幹。
五毒有歐,資料俺不九班的由其他各個系統小組提供,但是有些資料是隨機生成的一些描述性的文字,而該文字從固定的文字陣列而來。前端展示效果又要將隨機文字拆成幾個部分來。
正常的sql拼接成json還方便。
CONCAT('\"app\":{\"time\":\"', DATE_FORMAT(time, "%Y-%m-%d %T"), '\",\"days\":', days, case when typeTime is null then '' else CONCAT(',\"typeTime\":\"', DATE_FORMAT(typeTime, "%Y-%m-%d %T"), '\"') end,'}') 複製程式碼
隨機文字來了
學富五車:再美的氣質,也掩蓋不了你才華本質 足智多謀:腦力使用積極分子,非你莫屬 仗義執言:你的見解,面面俱到,深入人心 火眼金睛:獨特的洞察力,總能獲悉一切 見多識廣:最美的閱歷,就是沿路的風景 責任擔當:先天下之憂而憂,後天下之樂而樂
從上面可以看的出,它們之間一一對應的。
唯獨那些隨機文字著實思考片刻。來,我們層層剖析它。
擷取文字
mysql中怎麼從陣列中取隨機的文字,參考substring_index函式。分為兩步走,第一步先去倒數開始往前數倒數幾位,第二步再從新的陣列中取第一位。
substring_index(substring_index(array, '符合間隔', -n), '符合間隔', 1) 複製程式碼
構造隨機因子
現在再看看這個隨機因子怎麼取,參考rand()函式。
因為取的是-1到-7之間的隨機數。所以最終的效果就是如下。
-floor(rand()*7+1) 複製程式碼
取隨機範圍內的值可以參考這個公式
FLOOR(start_num + RAND() * (end_num - start_num + 1)) 複製程式碼
開始第一次擷取
隨機串擷取方法有了,隨機數也有了,開幹。
select user_id, CONCAT('\"desc\": {\"label\":\"', substring_index(substring_index('學富五車;足智多謀;仗義執言;火眼金睛;見多識廣;責任擔當;樂觀積極',';',-FLOOR(rand()*7+1)),';',1),'\"', ',\"description\": \"', substring_index(substring_index('再美的氣質,也掩蓋不了你才華本質;腦力使用積極分子,非你莫屬;你的見解,面面俱到,深入人心;獨特的洞察力,總能獲悉一切;最美的閱歷,就是沿路的風景;先天下之憂而憂,後天下之樂而樂;愛笑的你運氣一定不會差',';',-FLOOR(rand()*7+1)),';',1), '\"}' ) as report_content from data; 複製程式碼
結果發現對不上啊,【責任擔當】應該對應【先天下之憂而憂,後天下之樂而樂】,而結果出現部分對應到【再美的氣質,也掩蓋不了你才華本質】

努力第二次擷取
這次考慮到上回我們是把隨機因子放在sql裡沒句話裡,所以每次都執行了2次,生成是隨機因子就不一樣了,擷取的結果就對應不上,那,我們先在子查詢裡先把隨機因子生成後,再在外層用這個隨機因子這下應該不一樣了把。
select temp.user_id, CONCAT('\"desc\": {\"label\":\"', substring_index(substring_index('學富五車;足智多謀;仗義執言;火眼金睛;見多識廣;責任擔當;樂觀積極',';',temp.desc_index),';',1),'\"', ',\"description\": \"', substring_index(substring_index('再美的氣質,也掩蓋不了你才華本質;腦力使用積極分子,非你莫屬;你的見解,面面俱到,深入人心;獨特的洞察力,總能獲悉一切;最美的閱歷,就是沿路的風景;先天下之憂而憂,後天下之樂而樂;愛笑的你運氣一定不會差',';',temp.desc_index),';',1), '\"}' ) as report_content from (select user_id, -FLOOR(rand()*7+1) as desc_index from data) temp 複製程式碼
吐血的圖片在查詢中,從開頭看就看的出來,對應不上啦,前幾個就前部對應【愛笑的你運氣一定不會差】,愛笑的我,運氣就是這麼差。

改變下語句把隨機因子打印出來
select temp.user_id, desc_index, CONCAT(desc_index, '\"desc\": {\"label\":\"', substring_index(substring_index('學富五車;足智多謀;仗義執言;火眼金睛;見多識廣;責任擔當;樂觀積極',';',temp.desc_index),';',1),'\"', ',\"description\": \"', substring_index(substring_index('再美的氣質,也掩蓋不了你才華本質;腦力使用積極分子,非你莫屬;你的見解,面面俱到,深入人心;獨特的洞察力,總能獲悉一切;最美的閱歷,就是沿路的風景;先天下之憂而憂,後天下之樂而樂;愛笑的你運氣一定不會差',';',temp.desc_index),';',1), '\"}' ) as report_content from (select user_id, -FLOOR(rand()*7+1) as desc_index from data) temp 複製程式碼
********,前面這些打星號的,都是髒話,忽略它,隨機因子,明明在子查詢都生成了,為毛還是不一樣。

最終絞盡腦汁的擷取
本想在子查詢中使用rand()把隨機因子可以搞出來,哪成想,在外層的查詢時rand()又TMM的重算了一遍。
一頓參考一頓找資料,偶然間發現了問題所在
2017年有個哥們提了這樣的一個issue,就是上面的連結。
裡面說了一些情況,在mysql5.6裡,隨機數是一樣的,5.7裡隨機數不一樣。如果子查詢裡不使用表,隨機數也是一樣。剛剛好mysql就是5.7,剛剛好中招了。

根據作者和Roy Lyseng的建議,我用limit,沒想到,盡然闊以啦,老淚縱橫啊。
還是老外好,成功的解決方案,也會在issue裡說明下的。
改造後的最終樣子。
select temp.user_id, desc_index, CONCAT(desc_index, '\"desc\": {\"label\":\"', substring_index(substring_index('學富五車;足智多謀;仗義執言;火眼金睛;見多識廣;責任擔當;樂觀積極',';',temp.desc_index),';',1),'\"', ',\"description\": \"', substring_index(substring_index('再美的氣質,也掩蓋不了你才華本質;腦力使用積極分子,非你莫屬;你的見解,面面俱到,深入人心;獨特的洞察力,總能獲悉一切;最美的閱歷,就是沿路的風景;先天下之憂而憂,後天下之樂而樂;愛笑的你運氣一定不會差',';',temp.desc_index),';',1), '\"}' ) as report_content from (select user_id, -FLOOR(rand()*7+1) as desc_index from data limit 100000) temp 複製程式碼

