天天看點

hive 行轉列和列轉行的方法_有趣的SQL(4) 行轉列的複雜應用和優化思想

大家好,我是知數堂SQL 優化班老師 網名:騎龜的兔子

在之前的的系列文章中,有意思的SQL(3) 行轉列,列轉行和複制

已經給大家介紹了,行轉列,列轉行,複制等方法。

在這篇文章中,對其進行更深一層的應用。

需求如下,

有一個表如下圖所示

hive 行轉列和列轉行的方法_有趣的SQL(4) 行轉列的複雜應用和優化思想

現在有個需求是,我在畫面輸入

'10004,22744,24007' 要求傳回對應的三行資料

當然有很多種解決方案,一類是,在前端或者server端 用語言把輸入值分開,

還有一種是在資料庫端,本文介紹的是在資料庫端的方法,

當然還有 最簡單方案如下

hive 行轉列和列轉行的方法_有趣的SQL(4) 行轉列的複雜應用和優化思想

這種方案,也可以解決輸入值有空格的情況

hive 行轉列和列轉行的方法_有趣的SQL(4) 行轉列的複雜應用和優化思想

那這種方案的問題在哪呢?

先看下,這個表中是有索引的如下

hive 行轉列和列轉行的方法_有趣的SQL(4) 行轉列的複雜應用和優化思想

運作了,下面的SQL 從執行計劃中,可看出,走全表掃描了

hive 行轉列和列轉行的方法_有趣的SQL(4) 行轉列的複雜應用和優化思想

也就是說表越大,有可能越慢!

寫SQL 有幾個階段,第一個階段是為了熟悉各種文法,和實作各種需求階段

第二個階段是,寫出,更符合資料庫特點,符合優化思路的SQL

上面的SQL 就是滿足了需求,但是不符合優化。

如果寫成如下

hive 行轉列和列轉行的方法_有趣的SQL(4) 行轉列的複雜應用和優化思想

就可以有能滿足需求,有能達到優化效果的SQL!

那現在的問題是,怎麼把 '10004','22744','24007' 一行資料的變成3行資料的問題!

這樣總算,文章又回到,本文開篇,沒跑題~~

根據上篇文章,我們想把一行資料變成多行,我們需要複制

hive 行轉列和列轉行的方法_有趣的SQL(4) 行轉列的複雜應用和優化思想

這裡我用到了MySQL 8.0 開始支援的with 語句,

不支援的可以用臨時表代替。

其中 num 是為了複制而弄的中間表,可以了解為,我們中學的幾何題中,為了解決問題畫的輔助線~~。

上面的SQL 已經達到複制效果了,但是顯然,複制的有點多了,我們隻需要3行資料,但複制了5行,顯然不行,我們觀察下,結果發現我們如果複制的行數是逗号的個數+1 就可以了!

那怎麼表達呢,我們用原來的length-去掉逗号後length +1 就可以

hive 行轉列和列轉行的方法_有趣的SQL(4) 行轉列的複雜應用和優化思想

從上圖所示,可以看出,這樣就複制了我們想要的行數。

現在就剩下,怎麼截取的問題,我們想要的是第一行截取第一個,第二行第二個,第n行第n個 。。。

MySQL 8.0給我們提供了regexp_substr這樣的強大的函數,專門解決這樣的問題

當然還有别的解決方案,為了代碼的簡單,我就用了這個函數

hive 行轉列和列轉行的方法_有趣的SQL(4) 行轉列的複雜應用和優化思想

這樣我們就解決了,行轉列的問題,剩下的是把這部分帶到原來的SQL 中,

執行計劃如下,執行計劃稍微有點複雜,初學者比較難懂

hive 行轉列和列轉行的方法_有趣的SQL(4) 行轉列的複雜應用和優化思想

下面是運作結果,還是符合需求的

hive 行轉列和列轉行的方法_有趣的SQL(4) 行轉列的複雜應用和優化思想

為了,給大家一個直覺的感覺,我用大表salaries 表替換了原來的dept_emp表

然後運作SQL如下 運作了3.8 秒 !

hive 行轉列和列轉行的方法_有趣的SQL(4) 行轉列的複雜應用和優化思想

用修改之後代碼 行數太多,我把資料删了保留時間如下 0.01秒

用倍數的話。。。

hive 行轉列和列轉行的方法_有趣的SQL(4) 行轉列的複雜應用和優化思想

本文,通過一個簡單案例,給大家講述了,SQL開發過程中的幾個方法和優化思路,我們不僅僅開發過程中想到怎麼解決需求,若果想進一步,就需要考慮性能問題

謝謝大家~

我是知數堂SQL 優化班老師~ ^^

如有關于SQL優化方面疑問和一起交流的請加 并且 @兔子@知數堂SQL優化

hive 行轉列和列轉行的方法_有趣的SQL(4) 行轉列的複雜應用和優化思想