1. 程式人生 > >sql語句中多個union all的case when優化

sql語句中多個union all的case when優化

今天有點空,打算把報表專案中前人留下的一段sql優化下。
原sql大致如下(刪除了設計公司資料的敏感資訊):

select '現場司機' 環節,'勞斯萊斯' 品牌, 'CIQ 直接喂料' 採集專案, count(1) 統計數量  from test_table
	where 操作人 IN('張三','李四','王五','趙六','錢七')
	and 操作型別='PDI喂料移車' AND 原庫位='入庫點' AND 操作日期 >= '2017-09-01' AND 操作日期 <= '2017-11-30'			
union all
select '現場司機' 環節,'勞斯萊斯' 品牌, 'CIQ 入暫存' 採集專案, count(1) 統計數量  from test_table
	where 操作人 IN('張三','李四','王五','趙六','錢七') 
	and 操作型別='PDI暫存區移車' AND 原庫位='入庫點' AND 操作日期 >= '2017-09-01' AND 操作日期 <= '2017-11-30'		
union all
select '現場司機' 環節,'萊斯萊斯' 品牌, '暫存喂料' 採集專案, count(1) 統計數量  from test_table
	where 操作人 IN('張三','李四','王五','趙六','錢七') 
	AND 操作型別='PDI喂料移車' AND 原庫位='PDI暫存區' AND 操作日期 >= '2017-09-01' AND 操作日期 <= '2017-11-30'			
union all
select '現場司機' 環節,'勞斯萊斯' 品牌, '入庫' 採集專案, count(1) 統計數量 from test_table
	where 操作人 IN('張三','李四','王五','趙六','錢七')
	AND ((操作型別='移入立體庫' AND 原庫位 IN('PDI交接區', '維修交接區', 'PDI維修區', 'PDI喂料區', 'PDI暫存區', '待發區', '入庫點'))
		or (操作型別='移車' and left(原庫位,3) = 'PDI'))
	AND left(當前庫位,1) IN('H','W','K','T','A','E','Z','增','臨') AND 操作日期 >= '2017-09-01' AND 操作日期 <= '2017-11-30'			
union all
select '現場司機' 環節,'勞斯萊斯' 品牌, '發車' 採集專案, count(1) 統計數量  from test_table
	where 操作人 IN('張三','李四','王五','趙六','錢七')
	AND 操作型別='移入待發區' AND 操作日期 >= '2017-09-01' AND 操作日期 <= '2017-11-30'			
union all
select '現場司機' 環節,'勞斯萊斯' 品牌, '維修喂料' 採集專案, count(1) 統計數量  from test_table
	where 操作人 IN('張三','李四','王五','趙六','錢七') 
	AND ((操作型別 ='PDI喂料移車' AND 原庫位 <> '入庫點' AND LEFT(原庫位,3)  <> 'PDI') or 操作型別 ='PDI維修移車')
	AND 操作日期 >= '2017-11-01' AND 操作日期 <= '2017-11-30'			
union all
select '現場司機' 環節,'勞斯萊斯' 品牌, '維護移車' 採集專案, count(1) 統計數量 from test_table
	where 操作人 IN('張三','李四','王五','趙六','錢七')
	AND 操作型別='洗車/保養移車'  AND left(原庫位,1) NOT IN('洗','增') AND 操作日期 >= '2017-09-01' AND 操作日期 <= '2017-11-30'		
union all
select '現場司機' 環節,'勞斯萊斯' 品牌, '維護返庫移車' 採集專案, count(1) 統計數量  from test_table
	where 操作人 IN('張三','李四','王五','趙六','錢七')
	AND 操作型別 in('移入立體庫','移車') AND 原庫位='增值服務區' AND 操作日期 >= '2017-09-01' AND 操作日期 <= '2017-11-30'		
union all
select '現場司機' 環節,'勞斯萊斯' 品牌, '移車' 採集專案, count(1) 統計數量 from test_table
	where 操作人 IN('張三','李四','王五','趙六','錢七')
	and ((操作型別='移車' and left(原庫位,3) != 'PDI'  and 原庫位 != '增值服務區')
		or (操作型別='PDI暫存區移車' and 原庫位 != '入庫點')
		or (操作型別='移入立體庫' and 原庫位 = '臨時庫位'))  
	AND 操作日期 >= '2017-09-01' AND 操作日期 <= '2017-11-30'


原始查詢相當於將表格查詢了很多遍,然後查詢結果進行拼接,這樣效率註定不會很高,更主要時程式碼看著太雜亂,尤其是人員名字比較多的時候,很不利於後期維護。將上述查詢語句用case when進行優化,優化後sql如下:

select '現場司機' 環節,'勞斯萊斯' 品牌,A.subjects 採集專案,count(1) 統計數量 from (
	select (case when 操作型別='PDI喂料移車' AND 原庫位='入庫點' then 'CIQ 直接喂料'
		when 操作型別='PDI暫存區移車' AND 原庫位='入庫點' then 'CIQ 入暫存'
		when 操作型別='PDI喂料移車' AND 原庫位='PDI暫存區' then '暫存喂料'
		when ((操作型別='移入立體庫' AND 原庫位 IN('PDI交接區', '維修交接區', 'PDI維修區', 'PDI喂料區', 'PDI暫存區', '待發區', '入庫點'))
			or (操作型別='移車' and left(原庫位,3) = 'PDI'))
			AND left(當前庫位,1) IN('H','W','K','T','A','E','Z','增','臨') then '入庫'
		when 操作型別='移入待發區' then '發車'
		when (操作型別 ='PDI喂料移車' AND 原庫位 <> '入庫點' AND LEFT(原庫位,3)  <> 'PDI') or 操作型別 ='PDI維修移車' then '維修喂料'
		when 操作型別='洗車/保養移車'  AND left(原庫位,1) NOT IN('洗','增') then '維護移車'
		when 操作型別 in('移入立體庫','移車') AND 原庫位='增值服務區' then '維護返庫移車'
		when (操作型別='移車' and left(原庫位,3) != 'PDI'  and 原庫位 != '增值服務區')
			or (操作型別='PDI暫存區移車' and 原庫位 != '入庫點')
			or (操作型別='移入立體庫' and 原庫位 = '臨時庫位') then '移車'
		else '未確認' end) as subjects
	from TMP_INVENTORY where 操作人 IN('張三','李四','王五','趙六','錢七') AND 操作日期 >= '2017-09-01' AND 操作日期 <= '2017-11-30'
) A group by A.subjects

優化後採集專案會多一個“未確認”,這樣不僅不會影響原有的結果,反而會在結果中提示開發者有未考慮到的操作情況存在。

人員姓名需要外部傳入的話,可以參考bg_yf_license_weight ow on od.id = ow.order_id and ow.is_delete = 0

注意:並非所有的用到多個union all的情況都可以通過該方法優化,具體問題需要具體對待。