SQL行轉(zhuǎn)列應(yīng)用的動(dòng)態(tài)實(shí)現(xiàn)方式
概述:
SQL行轉(zhuǎn)列的需求,在項(xiàng)目中還是經(jīng)??梢姷模绕鋱?bào)表類的應(yīng)用,更是非常廣泛!上期我們講了SQL行轉(zhuǎn)列的靜態(tài)實(shí)現(xiàn)方式,本期搞一下行轉(zhuǎn)列的動(dòng)態(tài)實(shí)現(xiàn)方案,解決方案并不唯一,這里采用存儲(chǔ)過程的實(shí)現(xiàn)方式!
接下來我們?cè)敿?xì)講解下SQL動(dòng)態(tài)行轉(zhuǎn)列的實(shí)現(xiàn)步驟:
創(chuàng)建模擬數(shù)據(jù):
這里還是老套路,IT編程人入門的經(jīng)典學(xué)生選課表系列,學(xué)生表、課程表、成績(jī)表!就拿這套耳熟能詳?shù)谋斫Y(jié)構(gòu)進(jìn)行講解!


插入模擬的數(shù)據(jù),用于動(dòng)態(tài)行轉(zhuǎn)案例的使用!

先寫好靜態(tài)行轉(zhuǎn)列SQL:
這一步相對(duì)還是比較重要,畢竟我們要在一個(gè)靜態(tài)的行轉(zhuǎn)列基礎(chǔ)之上,構(gòu)建動(dòng)態(tài)的行轉(zhuǎn)列應(yīng)用,課程數(shù)據(jù)會(huì)有動(dòng)態(tài)變化,學(xué)生也會(huì)選擇新開的課程,這樣靜態(tài)模式勢(shì)必不會(huì)有效,但參照靜態(tài)模板,去開發(fā)動(dòng)態(tài)的模式,則更加有參照性!
- SELECT S.SID,S.sname,
- MAX(case c.cname when '數(shù)學(xué)' then sc.score else 0 end) as 數(shù)學(xué),
- MAX(case c.cname when '語文' then sc.score else 0 end) as 語文,
- MAX(case c.cname when '英語' then sc.score else 0 end) as 英語
- FROM Student as S
- LEFT JOIN SC AS SC ON S.sid = SC.SID
- LEFT JOIN Course AS C ON C.cid = SC.CID
- GROUP BY S.sid,S.sname

通過測(cè)試,數(shù)據(jù)效果沒有問題,正是我們期待的樣子!
編寫動(dòng)態(tài)腳本:
動(dòng)態(tài)行轉(zhuǎn)列無疑需要使用SQL編程的技術(shù),動(dòng)態(tài)的遞歸課程名稱,這樣才可以一勞永逸的解決問題!
先編寫動(dòng)態(tài)的SQL腳本:
- DECLARE @SQL VARCHAR(MAX)
- SELECT @SQL = ' SELECT S.SID,S.SNAME '
- SELECT @SQL = @SQL + ' , ISNULL(MAX(CASE c.cname WHEN '''+cname+''' THEN sc.score END ),0) AS '''+c.cname+''' '
- FROM Course AS C
- print @sql
- SELECT @SQL = @SQL + ' FROM Student as S
- LEFT JOIN SC AS SC ON S.sid = SC.SID
- LEFT JOIN Course AS C ON C.cid = SC.CID
- GROUP BY S.sid,S.sname'
- print @sql
- EXEC (@SQL)
測(cè)試結(jié)果與靜態(tài)SQL完全一致,看來問題已經(jīng)解決,接下來就是優(yōu)化的問題了!

將上述的動(dòng)態(tài)腳本封裝成存儲(chǔ)過程,第一可以盡量地提升查詢效率,第二方便代碼段的調(diào)用!
- CREATE PROC StudentScore_Proc
- AS
- BEGIN
- DECLARE @SQL NVARCHAR(MAX)
- SELECT @SQL = N' SELECT S.SID,S.SNAME '
- SELECT @SQL = @SQL + N' , ISNULL(MAX(CASE c.cname WHEN '''+cname+''' THEN sc.score END ),0) AS '''+c.cname+''' '
- FROM Course AS C
- SELECT @SQL = @SQL + N' FROM Student as S
- LEFT JOIN SC AS SC ON S.sid = SC.SID
- LEFT JOIN Course AS C ON C.cid = SC.CID
- GROUP BY S.sid,S.sname'
- print @sql
- EXECUTE sp_executesql
- @STMT = @SQL
- END
- EXEC dbo.StudentScore_Proc
封裝完存儲(chǔ)過程,我們?cè)賵?zhí)行一下,看看結(jié)果!果然沒有任何問題,與預(yù)期完全一致!

這時(shí)候我們更改一下數(shù)據(jù),課程表中新增物理、化學(xué)兩門課程,諾克薩斯之手分別選擇了兩門課程,蓋倫僅僅選擇了化學(xué),武器大師逃學(xué),倆門課都沒有選擇。
- INSERT INTO Course SELECT 4,'物理'
- INSERT INTO Course SELECT 5,'化學(xué)'
- INSERT INTO SC SELECT 1,4,99
- INSERT INTO SC SELECT 1,5,88
- INSERT INTO SC SELECT 2,5,77
- EXEC dbo.StudentScore_Proc
數(shù)據(jù)改變之后,我們繼續(xù)測(cè)試一下,再次執(zhí)行我們編寫好的存儲(chǔ)過程,結(jié)果非常完美,隨著數(shù)據(jù)的變化,查詢的結(jié)果集也是對(duì)應(yīng)的變化,非常NICE,大功告成了!

總結(jié)一下:
連續(xù)倆篇的文章更新,SQL行轉(zhuǎn)列在項(xiàng)目中的應(yīng)用都已經(jīng)涵蓋了。即將步入年底了,肯定有很多小伙伴被客戶、領(lǐng)導(dǎo)追著搞各種報(bào)表,希望對(duì)小伙伴們有些許的幫助。