SQL優化 - 同比計算


記錄一次SQL優化, 在計算同比的時候. 就太久沒有寫語句了, 能力在逐漸下滑, 思維也是, 感覺還是有點可怕的. 自從轉業務以來, 就基本沒有碰過代碼這方面了. 甚至連 SQL 都開始要搜索了. 而我日常更多是讓專業的開發來做, 我負責跟進度, 也不知道我這樣存在的意義是否有價值. 正好又在弄BI, 然后呢根據過往經驗, 處理邏輯還是盡量在后台處理好, 前台就直接展示即可.

有這樣一個基礎的算同比的需求, 分為兩步. 一個是要對某字段進行合並, 然后基於合並再進行匯總和計算同比. 我的 1.0 版本是這樣的.

1.0 臨時表 + 2表連接

用的是 Sql Server

WITH A AS (
	SELECT 
	  CASE
	  WHEN AGENT IN ('AA', 'AAA')       THEN 'AA'
	  WHEN AGENT IN ('BB', 'BBB')       THEN 'BB'
	  WHEN AGENT IN ('CC', 'CCC')       THEN 'CCC'
	  ELSE AGENT END AS 代理
	  , 品類
	  , 銷售時間
	  , 數量 
	FROM AAAAA
	WHERE 是否電商 = 1
	  AND 品類 IN ('A品類', 'B品類', 'C品類')
 ) 
 -- MAIN
-- 當月銷量
SELECT 
  B.*
  , C.當月銷量 AS 同期19月銷
FROM (
	SELECT 
	  A.代理
	  , A.品類
	  , SUM(A.數量)     AS 當月銷量
	FROM A
	WHERE 銷售時間  >= DATEFROMPARTS(YEAR(GETDATE()),MONTH(GETDATE()), 1)
	   AND 銷售時間 <= GETDATE()
	GROUP BY 代理, 品類
) AS B 
-- 19年同期銷量
LEFT JOIN (
	SELECT 
	  代理
	  , 品類
	  , SUM(數量)     AS 當月銷量
	FROM A
	WHERE 銷售時間  >= DATEFROMPARTS(2019, MONTH(GETDATE()), 1)
	   AND 銷售時間 <= DATEFROMPARTS(2019, MONTH(GETDATE()), DAY(GETDATE())-1)
	GROUP BY 代理, 品類
) AS C
  ON B.代理 = C.代理 AND B.品類 = C.品類
  
ORDER BY B.當月銷量 DESC 
  

問題點

  • 為了處理一個字段, 建了個臨時查詢, 相等於遍歷了一整個表
  • 算同比, 用到了 2個表 (當期, 同期) 進行拼接 (各自還執行了一次 group by )
  • 代碼冗余, 結構不清晰

對於計算同比這塊, 其實結構是完全一樣的, 只是 時間 不同而已, 那判斷時間就可以了, 完全沒必要用 Join 搞兩張表.

2.0 用 Case when 時間 代替表 Join 算同比

WITH A AS (
	SELECT 
	  CASE
	  WHEN AGENT IN ('AA', 'AAA')       THEN 'AA'
	  WHEN AGENT IN ('BB', 'BBB')       THEN 'BB'
	  WHEN AGENT IN ('CC', 'CCC')       THEN 'CCC'
	  ELSE AGENT END AS 代理
	  , 品類
	  , 銷售時間
	  , 數量 
	FROM AAAAA
	WHERE 是否電商 = 1
	  AND 品類 IN ('A品類', 'B品類', 'C品類')
 ) 
 
 -- MAIN 
 SELECT 
   代理
   , 品類
   , SUM(CASE WHEN 
         銷售時間 BETWEEN DATEFROMPARTS(YEAR(GETDATE()),MONTH(GETDATE()), 1) AND GETDATE()
         THEN 數量 ELSE 0 END) AS 當月銷量
   , SUM(CASE WHEN 
         銷售時間 BETWEEN DATEFROMPARTS(2019, MONTH(GETDATE()), 1) AND DATEFROMPARTS(2019, MONTH(GETDATE()), DAY(GETDATE())-1)
         THEN 數量 ELSE 0 END) AS 同期19年月銷量
 FROM A
 GROUP BY 代理, 品類
 ORDER BY 當月銷量 DESC 
 

問題點

  • 是減少了查詢, 極大優化了, 但 臨時表 也是不必要的, 可以一步到位.
  • 美中不足, 尚可再優化

3.0 將 Case when 結合 Group By 一步到位

sql server 很煩的一點是, 不能同級引用...

 SELECT 
	  CASE
	  WHEN AGENT IN ('AA', 'AAA')       THEN 'AA'
	  WHEN AGENT IN ('BB', 'BBB')       THEN 'BB'
	  WHEN AGENT IN ('CC', 'CCC')       THEN 'CCC'
	  ELSE AGENT END AS 代理
   , 品類
   , SUM(CASE WHEN 
         銷售時間 BETWEEN DATEFROMPARTS(YEAR(GETDATE()),MONTH(GETDATE()), 1) AND GETDATE()
         THEN 數量 ELSE 0 END) AS 當月銷量
   , SUM(CASE WHEN 
         銷售時間 BETWEEN DATEFROMPARTS(2019, MONTH(GETDATE()), 1) AND DATEFROMPARTS(2019, MONTH(GETDATE()), DAY(GETDATE())-1)
         THEN 數量 ELSE 0 END) AS 同期19年月銷量
 FROM AAAAA
 WHERE 是否電商 = 1
   AND 品類 IN ('A品類', 'B品類', 'C品類')
 GROUP BY 品類, CASE
	  WHEN AGENT IN ('AA', 'AAA')       THEN 'AA'
	  WHEN AGENT IN ('BB', 'BBB')       THEN 'BB'
	  WHEN AGENT IN ('CC', 'CCC')       THEN 'CCC'
	  ELSE AGENT END 
 ORDER BY 當月銷量 DESC 
 

抽空還是要多練練, 這個很容易就忘掉了.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM