<a href="http://www.jb51.net/article/78388.htm">原文連結</a>
本文介紹的執行個體成功的實作了動态行轉列。下面我以一個簡單的資料庫為例子,說明一下。
資料表結構
這裡我用一個比較簡單的例子來說明,也是行轉列的經典例子,就是學生的成績
三張表:學生表、課程表、成績表
學生表
就簡單一點,學生學号、學生姓名兩個字段
課程表
課程編号、課程名
成績表
學生學号、課程号、成績
以上就是資料庫表的結構了,這裡沒有建立外鍵,但是根據表的結構,可以清楚的看到成績表中的學号和課程号是與學生表、課程表分别關聯起來的。
資料準備
為什麼要行轉列
這是我們進行成績查詢的時候看到的這種縱列的結果,但是一般的時候,我們想要看到下圖這種結果
那麼需要這樣的結果就要進行行轉列來操作了。
怎麼行轉列
像得到上圖的結果,一般的行轉列,我們隻需要這麼做
靜态行轉列
看上面的語句可以看出,我們是在知道固定的幾門課程之後,可以使用
這樣的語句來實作行轉列
但我們都知道,課程不僅僅這幾門,如果用上面的語句去寫,第一要确定有多少課程,這麼多課程的課程名要再拿出來,那樣的話寫一個查詢語句下來,可是要寫很多了。那麼就想能不能動态進行行轉列的操作?答案當然是肯定的了!
動态行轉列
那麼如何進行動态行轉列呢?
首先我們要動态擷取這樣的語句
而不是像上面那樣一句句寫出來,那如何得到這樣的語句呢?
這裡就要用到SQL語句拼接了。具體就是下面的語句
得到的結果就是
對,沒錯,就是我們上面進行行轉列查詢要用的語句,那樣就不用知道多少課程和這些課程的名字,隻要這樣幾行代碼便可以得到動态的列了。
動态的列是拿到了,那如何再結合SQL語句進行查詢得到結果呢?
這裡要說明一點,因為用到了拼接函數,如果像上面的查詢語句,隻是把那幾行語句替換掉,也就是下面這樣
然而得到的結果卻是這樣的
這裡我就不多做贅述了,想必大家也明白。那麼既然這樣不行,那該怎麼做呢?
沒錯,這裡就要像普通的那些語句那樣,進行聲明,将語句拼接完整之後,再執行,也就是下面這樣
直接執行這些語句,得到如下結果。
沒錯,和開始的時候那種全部拼出來的語句一樣,這樣就實作了動态行轉列的目的了。而且我們不用知道多少課程,也無需把這些課程名一一列出來。
當然這個語句拼接中的查詢可以加入條件查詢,比如我們要查詢學号是1003的成績
也就是下面這樣
語句則如下
對比前面的語句,我們可以看到在第二行的Left join後面我改了一些,還有就是前面的變量加了一個@stuid [ 注:這裡的 @ 符号是在SQL語句定義變量習慣用法,我個人了解應該是用來區分吧!]
那麼問題來了,行轉列的查詢已經實作了,怎麼标題中還寫着存儲過程?對,沒錯,就是存儲過程!
像上面的語句,我們如果直接在MySQL中操作是沒問題的,但如果用到項目中,那麼這個語句顯然我們沒法用,而且我這次做的項目是結合使用MyBatis,大家都知道在MyBatis中的XML檔案中可以自己寫SQL語句,但是這樣的很顯然我們沒法放到XML檔案中。
而且最關鍵的是,這裡不能用 If 條件,好比我們要判斷學号是否為空或者等于0再加上條件進行查詢,可是這裡不支援。
沒錯就是下面這樣
對,我就是加上 if 之後人家就是不支援,就是這麼任性。
是以就要用到存儲過程啦,而且用存儲過程的好處是,友善我們調用,相當于一個函數,其他可能也是類似的查詢不需再重複寫代碼,直接調存儲過程就好,還能随心所欲的加上if條件判斷,多麼美好的事情,哈哈~。
那麼說到存儲過程,這裡該如何寫呢?
建立存儲過程的語句我就不多寫了,這裡呢把上面的查詢語句直接放到建立存儲過程的begin和end直接就可以了,如下:
嗯,對比上面簡單的SQL語句可以看出,這裡使用了 if 語句,對學号進行了判斷
不過這裡要注意一點,這裡的if語句不像我們平時java啊那種寫法也就是下面
if(條件)
{
要執行的語句塊
}
對,在SQL裡面的if語句不一樣,不需要括号啊什麼的,就像直接說英文一樣
嗯,就是這麼簡單明了,如果條件滿足,那麼就怎麼樣,然後結束。
然後我們就可以傳參數調用這個SP了
得到如下結果
當然我們也可以直接傳個空串過去
同樣得到我們想要的結果
好了,以上就是這次我在MySQL進行動态行轉列的實作過程。
總結及問題
開始的時候,隻想到要行轉列,寫着寫着突然發現要動态的,因為我不确定到底有多少列。
在網上各種找資料,然而看不太懂!
後來,參考了Pivot table with dynamic columns in MySQL這個,才寫出來的。
然後是各種問題,先是SQL語句中加入if條件,我像平時寫java那樣,發現并沒有什麼用,網上也說就是這種
可是我這麼寫了之後并沒有什麼用,還是報錯,找了不少之後才發現原來不是這麼寫的,然後改了過來。
改完之後我以為可以了,可是,發現依舊不行。然後我就在想是不是這裡不能用if判斷,因為不是一個function或者procedure,于是我就寫建立procedure的語句。
改造完之後,procedure成功的建立了。那建立完我就試試能不能,調用procedure之後,當當當當,結果出來了。
嗯,這個過程還是收獲很多的,對MySQL的行轉列,以及存儲過程,還有在SQL語句中的使用不一樣的地方等。
而且,這個行轉列的實作了之後,這個項目基本上沒啥大問題了對資料的處理,相當好啊,哈哈~
以上就是我在行轉列實作的過程中所有的内容,相對來說,我覺得,這裡寫的很清楚很明了了,是以隻要你有耐心看完并認真研究的話,這個内容對你的行轉列還是有很大裨益的。
PS:如果生成的變量長度較長,導緻拼接的sql有問題,可以通過設定如下變量來調整