sql語句中多個union all的case when優化
阿新 • • 發佈:2018-12-23
今天有點空,打算把報表專案中前人留下的一段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的情況都可以通過該方法優化,具體問題需要具體對待。