[MSSQL]採用pivot函數實現動態行轉列

環境要求:2005+ 在日常需求中經常會有行轉列的事情需求處理,如果不是動態的行,那麼我們可以採取case when 羅列處理。 在sql 2005以前處理動態行或列的時候,通常採用拼接字符串的方法處理,在2005以後新增了pivot函數之後,我可以利用這樣函數來處理。 1.

 

環境要求:2005+

在日常需求中經常會有行轉列的事情需求處理,如果不是動態的行,那麼我們可以採取case when 羅列處理。

在sql 2005以前處理動態行或列的時候,通常採用拼接字符串的方法處理,在2005以後新增了pivot函數之後,我可以利用這樣函數來處理。

1.動態SQL注入式判斷函數

--既然是用到了動態SQL,就有一個老話題:SQL注入。建一個注入性字符的判斷函數。

CREATE FUNCTION [dbo].[fn_CheckSQLInjection]

(

 @Col nvarchar(4000)

)

RETURNS BIT --如果存在可能的注入字符返回true,反之返回false

AS

BEGIN

DECLARE @result bit;

  IF  

     UPPER(@Col) LIKE UPPER(N'%0x%')

  OR UPPER(@Col) LIKE UPPER(N'%;%')

  OR UPPER(@Col) LIKE UPPER(N'%''%')

  OR UPPER(@Col) LIKE UPPER(N'%--%')

  OR UPPER(@Col) LIKE UPPER(N'%/*%*/%')

  OR UPPER(@Col) LIKE UPPER(N'%EXEC%')

  OR UPPER(@Col) LIKE UPPER(N'%xp_%')

  OR UPPER(@Col) LIKE UPPER(N'%sp_%')

  OR UPPER(@Col) LIKE UPPER(N'%SELECT%')

  OR UPPER(@Col) LIKE UPPER(N'%INSERT%')

  OR UPPER(@Col) LIKE UPPER(N'%UPDATE%')

  OR UPPER(@Col) LIKE UPPER(N'%DELETE%')

  OR UPPER(@Col) LIKE UPPER(N'%TRUNCATE%')

  OR UPPER(@Col) LIKE UPPER(N'%CREATE%')

  OR UPPER(@Col) LIKE UPPER(N'%ALTER%')

  OR UPPER(@Col) LIKE UPPER(N'%DROP%')

  SET @result=1

 ELSE

  SET @result=0

 return @result

END

GO

2.需求:

--通過日期查詢幾個表聯合,按照檢驗項目分類,按日期橫向展示

select a.檢驗項目 , CONVERT(char(10),a.日期,120)日期,Convert(decimal(18,2),cast((SUM(a.測試數量)-SUM(a.不良數量)) as decimal(18,2))/sum(測試數量))*100  as 良率 

--into  #tempcob

from (select 日期,檢驗項目, 測試數量, 不良數量 from 製程COB成測 union all

select 日期,檢驗項目, 測試數量, 不良數量 from 製程COB外觀 union all

             select 日期,檢驗項目,測試數量, 不良數量 from 製程COB綁測 union all

select 送檢日期,'FQC_COB_檢驗',檢驗數量,不合格數量 from 製程FQC_COB_檢驗 

  ) as a 

  where CONVERT(char(10),日期,120)>='2014-10-01'  and CONVERT(char(10),日期,120)<= '2014-10-30'

 group by a.檢驗項目,a.日期

3.解決方案:

--抓取數據寫入臨時表#tempcob

select a.檢驗項目 , CONVERT(char(10),a.日期,120)日期,Convert(decimal(18,2),cast((SUM(a.測試數量)-SUM(a.不良數量)) as decimal(18,2))/sum(測試數量))*100  as 良率 

into  #tempcob

from (select 日期,檢驗項目, 測試數量, 不良數量 from 製程COB成測 union all

select 日期,檢驗項目, 測試數量, 不良數量 from 製程COB外觀 union all

             select 日期,檢驗項目,測試數量, 不良數量 from 製程COB綁測 union all

select 送檢日期,'FQC_COB_檢驗',檢驗數量,不合格數量 from 製程FQC_COB_檢驗 

  ) as a 

  where CONVERT(char(10),日期,120)>='2014-10-01'  and CONVERT(char(10),日期,120)<= '2014-10-30'

 group by a.檢驗項目,a.日期 

  

--查看臨時表數據,取分佈日期(不重複)

--select   日期 from #tempcob

--select  distinct 日期 from #tempcob

DECLARE @SQL NVARCHAR(4000)=N'';

--這裏使用了xml處理來處理類組字符串

SET @SQL=STUFF((SELECT N','+QUOTENAME(b.日期) FROM (select  distinct 日期 from #tempcob) as b

 FOR XML PATH('')),1,1,N''); 

--加入了xml處理和SQL注入預防判斷

IF  dbo.fn_CheckSQLInjection(@SQL)=0 

SET @SQL='select * from #tempcob pivot (max(良率) for 日期 in ('+@SQL+')) as tt'

EXEC(@SQL);

drop table #tempcob

 

親測代碼

/*動態行轉列,取得設計清單表及服務費明細並動態彙總分類費用*/
/*select * into #tmp_pms_wzfw 
from 
(
select project_code, treename, totalprice 
from PMS_MID_DESIGN_MATERIALS 
where treename is not null
--group by project_code, treename
union
select project_code, treename, totalprice 
from PMS_MID_DESIGN_SERVICE
where treename is not null
--group by project_code, treename
) P
*/

select L.orderStatus, P.project_code, P.treename, P.totalprice, L.twrCnstrctCost, L.roomCnstrctCost, L.fciliCnstrctCost, L.elecIndcFee --into #tmp_pms_wzfw 
into #tmp_pms_wzfw 
from 
(
select project_code, treename, totalprice 
from PMS_MID_DESIGN_MATERIALS 
where treename is not null
--group by project_code, treename
union
select project_code, treename, totalprice 
from PMS_MID_DESIGN_SERVICE
where treename is not null
--group by project_code, treename
) P
left join CRM_ORDER_STANDARD L on project_code = prjId

DECLARE @SQL NVARCHAR(4000)=N'';

--這裏使用了xml處理來處理類組字符串

SET @SQL=STUFF((SELECT N'],['+ treename FROM (select distinct treename from #tmp_pms_wzfw where treename is not null and totalprice > 0) b  order by treename FOR XML PATH('')),1,2,N'') + ']'; 
--select @SQL

--加入了xml處理和SQL注入預防判斷

IF  dbo.fn_CheckSQLInjection(@SQL)=0 

SET @SQL='select * from (select * from #tmp_pms_wzfw where project_code in (select [項目編碼] from tmp_5Gprj)) A pivot (sum(totalprice) for treename in ('+@SQL+')) as tt'

EXEC(@SQL);

drop table #tmp_pms_wzfw

 

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