---
# System prepended metadata

title: '第四章:'

---

###### tags: SQL


> rows between unbounded preceding and current row
> https://localcoder.org/what-is-rows-unbounded-preceding-used-for-in-teradata
# 第四章:

```
計算過去最多七日間的平均營收金額
SELECT dt,
	   SUM(purchase_amount) AS total_amount,
       --計算過去最多七日間的平均營收金額
       AVG(SUM(purchase_amount)) OVER(ORDER BY dt ROWS BETWEEN 6 preceding and current ROW) AS seven_day_ave,
       --嚴謹計算過去七日間的平均營收金額
       CASE
       		WHEN 7 = COUNT(*) OVER(ORDER BY dt ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) 
            THEN AVG(SUM(purchase_amount)) OVER(ORDER BY dt ROWS BETWEEN 6 PRECEDING AND CURRENT ROW)
       END AS seven_day_avg_strict
FROM purchase_log
GROUP BY dt
ORDER BY dt
```
---
```
--彙總每日營收與當月累計營收
SELECT dt,
	   --結取年月
       substring(dt, 1, 7) AS year_month,
       SUM(purchase_amount) AS total_amount,
       SUM(SUM(purchase_amount)) OVER(PARTITION BY substring(dt, 1, 7) ORDER BY dt ROWS UNBOUNDED PRECEDING)
FROM purchase_log
GROUP BY dt
ORDER BY dt
```
---
```
--將每日營收轉換成鄰時的資料表,並在daily_purchase資料表計算當月累計營收
WITH daily_purchase AS(
	SELECT dt,
  		   substring(dt, 1, 4) AS year,
  		   substring(dt, 6, 2) AS month,
  		   substring(dt, 9, 2) AS date,
  		   SUM(purchase_amount) AS purchase_amount
  	FROM purchase_log
    GROUP BY dt
)

SELECT dt,
	   concat(year, '-', month) AS year_month,
       purchase_amount,
       SUM(purchase_amount) OVER(PARTITION BY year, month ORDER BY dt ROWS UNBOUNDED PRECEDING) AS agg_amount
FROM daily_purchase
ORDER BY dt

```

---
```
--計算每月營收和年成長率
WITH daily_purchase AS (
	SELECT dt, 
  		   substring(dt, 1, 4) AS year,
  		   substring(dt, 6, 2) AS month,
  		   substring(dt, 9, 2) AS date,
  		   SUM(purchase_amount) AS purchase_amount
  	FROM purchase_log
    GROUP BY dt
)

SELECT month,
	   SUM(CASE year WHEN '2014' THEN purchase_amount END) AS amount_2014,
       SUM(CASE year WHEN '2015' THEN purchase_amount END) AS amount_2015,      
       100.0 * SUM(CASE year WHEN '2015' THEN purchase_amount END) / 
       	       SUM(CASE year WHEN '2014' THEN purchase_amount END) AS rate
FROM daily_purchase              
GROUP BY month
ORDER BY month
```
---
```
--建立2015年營收的Z圖表
WITH daily_purchase AS (
	SELECT dt, 
  		   substring(dt, 1, 4) AS year,
  		   substring(dt, 6, 2) AS month,
  		   substring(dt, 9, 2) AS date,
  		   SUM(purchase_amount) AS purchase_amount
  	FROM purchase_log
    GROUP BY dt
), 
	monyhly_amount AS (
	--彙總每月營收
    SELECT year, 
      	   month,
      	   SUM(purchase_amount) AS amount
    FROM daily_purchase
    GROUP BY year, month
),
	calc_index AS (
	SELECT year,
      	   month,
      	   amount,
    	   --計算2015年的累計營收
      	   SUM(CASE WHEN year = '2015' THEN amount END) OVER(ORDER BY year, month ROWS UNBOUNDED PRECEDING) AS agg_amount, 
      	   --計算從當月開始到11個月之前的合計營收(移動年營收)
      	   SUM(amount) OVER(ORDER BY year, month ROWS BETWEEN 11 PRECEDING AND CURRENT ROW) AS year_avg_amount
    FROM monyhly_amount
    ORDER BY year, month
)

--最後只擷取2015年的數據
SELECT concat(year, '-', month) AS year_month,
	   amount,
       agg_amount,
       year_avg_amount
FROM calc_index
WHERE year = '2015'
ORDER BY year_month

 
```
---
```
--彙總營收相關指標
WITH daily_purchase AS (
	SELECT dt,   		    
  		   substring(dt, 1, 4) AS year,
  		   substring(dt, 6, 2) AS month,
  		   substring(dt, 9, 2) AS date,
  		   SUM(purchase_amount) AS purchase_amount
  	FROM purchase_log
    GROUP BY dt
), monthly_purchase AS (
	SELECT year,
  		   month,
  		   --SUM(orders) AS orders,
  		   AVG(purchase_amount) AS avg_amount,
  	 	   SUM(purchase_amount) AS monthly
  	FROM daily_purchase
  	GROUP BY year, month
)

SELECT concat(year, '-', month) AS year_month,
       avg_amount,
       monthly,
       SUM(monthly) OVER(PARTITION BY year ORDER BY month ROWS UNBOUNDED PRECEDING) AS agg_amount,
       --取得前12個月營收
       LAG(monthly, 12) OVER(ORDER BY year, month) AS last_year, 
       --計算當月營收和12個月前營收的比值
       100.0 * monthly / LAG(monthly, 12) OVER(ORDER BY year, month) AS rate
FROM monthly_purchase
ORDER BY year_month
       
```

---
```
WITH sub_category_amount AS (
  	--彙總小類別的銷售金額
	SELECT category AS category,
  		   sub_category AS sub_category,
  		   SUM(price) AS amount
 	FROM purchase_detail_log
  	GROUP BY category,
  			 sub_category  		 
), category_amount AS (
  	--彙總大類別的銷售金額
	SELECT category AS category,
  		   'all' AS sub_category,
  		   SUM(price) AS amount
  	FROM purchase_detail_log
  	GROUP BY category
), total_amount AS (
   --計算全體銷售總額
   SELECT 'all' AS category,
  		  'all' AS sub_category,
  		  SUM(price) AS amount
   FROM purchase_detail_log
)
 
 
SELECT cast(category as text), cast(sub_category as text), cast(amount as text)
FROM sub_category_amount
UNION ALL
SELECT cast(category as text), cast(sub_category as text), cast(amount as text)
FROM category_amount
UNION ALL
SELECT cast(category as text), cast(sub_category as text), cast(amount as text)
FROM total_amount


```
---
```
--使用ROLLUP 同時取得類別銷售金額和小計
SELECT COALESCE(category, 'all') AS category,
	   COALESCE(sub_category, 'all') AS sub_category,
       SUM(price) AS amount
FROM purchase_detail_log
GROUP BY ROLLUP(category, sub_category)
 
```
---
```
--使用 GROUPING SETS
SELECT
    category,
    sub_category, 
    SUM (price) amount
FROM
    purchase_detail_log
GROUP BY
    GROUPING SETS(
        (category,sub_category),
        (category),
        (sub_category) 
    ); 
```

---
```
--計算營收組成的累計百分比與ABC Rank
WITH monthly_sales AS (
	SELECT category,
  		   --計算各類別的營收
  		   SUM(price) AS amount
    FROM purchase_detail_log
  	--將數據範圍限制在目標月份
  	WHERE dt BETWEEN '2015-12-01' AND '2015-12-31'
    GROUP BY category
), sales_composition_ratio AS (
	SELECT category,
  		   amount,
  		   --所佔百分比: 100.0 * 類別營收 / 全體營收
  		   100.0 * amount / SUM(amount) OVER() compositon_ratio,
  		   --累計百分比: 100.0 * 類別累計營收 / 全體營收
  		   100.0 * SUM(amount) OVER(ORDER BY amount DESC) / SUM(amount) OVER() AS cumulative_ratio
  
  	FROM monthly_sales
)

SELECT *,
	   --根據累計百分比進行分級
       CASE
       		WHEN cumulative_ratio BETWEEN 0  AND 70  THEN 'A'
            WHEN cumulative_ratio BETWEEN 70 AND 90  THEN 'B'
            WHEN cumulative_ratio BETWEEN 90 AND 100 THEN 'C'
       END
FROM sales_composition_ratio
ORDER BY amount DESC
```
---

```
--取得建立 Fan chart 所需之數據
--注意重點:採取哪個時間點的交售額作為基礎
WITH daily_category_amount AS (

   SELECT dt,
  		  category,
  		  substring(dt, 1, 4) AS year,
  		  substring(dt, 6, 2) AS month,
  		  substring(dt, 9, 2) AS date,
  		  price
   FROM purchase_detail_log
   GROUP BY dt, 
  			category,
  			price
	
), monthly_category_amount AS (

	SELECT concat(year, '-', month) AS year_month,
  	       category,
  		   SUM(price) AS price
    FROM daily_category_amount
  	GROUP BY year, 
  			 month,
  			 category
  
)

SELECT year_month,
	   category,
       price,
       FIRST_VALUE(price) OVER (PARTITION BY year_month, category ORDER BY year_month, category ROWS UNBOUNDED PRECEDING) AS base_amount,
       100.0 * price / FIRST_VALUE(price) OVER (PARTITION BY category ORDER BY year_month, category ROWS UNBOUNDED PRECEDING) AS rate
FROM monthly_category_amount
ORDER BY year_month, 
 		 category
```


---
```
--計算各數據所屬階級
WITH stats AS (

	SELECT MAX(price) + 1 AS max_price, -- +1 是為了能將所有數據都納入所指定的階級中
  		   MIN(price) AS min_price,
  		   MAX(price) + 1 - MIN(price) AS range_price, --價格的範圍
  		   10 AS bucket_num --階級數
    FROM purchase_detail_log
  
), purchase_log_with_bucket AS (

	SELECT price,
  		   min_price,
  		   price - min_price AS diff,  --標準化價格:目標價格減去最小價格
		   1.0 * range_price / bucket_num AS bucket_range,  --階級範圍: 全體價格區間除以階級數
  		   --階級的判定: FLOOR(標準化價格/階級範圍)，由於index是從1開始所以加上1
  		   FLOOR(1.0 * (price - min_price) / (1.0 * range_price / bucket_num)) + 1 AS bucket 
    FROM purchase_detail_log, stats
  
)
  
SELECT *
FROM purchase_log_with_bucket
 
```

---
```
--取得建立直方圖所需之數據
WITH stats AS (

	SELECT MAX(price) + 1 AS max_price, -- +1 是為了能將所有數據都納入所指定的階級中
  		   MIN(price) AS min_price,
  		   MAX(price) + 1 - MIN(price) AS range_price, --價格的範圍
  		   10 AS bucket_num --階級數
    FROM purchase_detail_log
  
), purchase_log_with_bucket AS (

	SELECT price,
  		   min_price,
  		   price - min_price AS diff,  --標準化價格:目標價格減去最小價格
		   1.0 * range_price / bucket_num AS bucket_range,  --階級範圍: 全體價格區間除以階級數
  		   --階級的判定: FLOOR(標準化價格/階級範圍)，由於index是從1開始所以加上1
  		   FLOOR(1.0 * (price - min_price) / (1.0 * range_price / bucket_num)) + 1 AS bucket 
    FROM purchase_detail_log, stats
  
)
  
SELECT bucket,
	   --計算階層的上限與下限
	   min_price + bucket_range * (bucket - 1) AS lower_limit,
       min_price + bucket_range * bucket AS upper_limit,
       --計算次數
       COUNT(price) AS num_purchase,
       --計算各階層的合計金額
       SUM(price) AS total_amount
FROM purchase_log_with_bucket
GROUP BY bucket, 
		 min_price, 
         bucket_range
ORDER BY bucket
 
```


---
```
--手動調整直方圖的上限與下限

WITH stats AS (
	
	SELECT 5000 AS max_price, --價格的最大值
  		   0 AS min_price, --價格的最小值
  		   5000 AS range_price, --價格區間
   		   10 AS bucket_num
    FROM purchase_detail_log

), purchase_log_with_bucket AS (

	SELECT price,
  		   min_price,
  		   price - min_price AS diff,  --標準化價格:目標價格減去最小價格
		   1.0 * range_price / bucket_num AS bucket_range,  --階級範圍: 全體價格區間除以階級數
  		   --階級的判定: FLOOR(標準化價格/階級範圍)，由於index是從1開始所以加上1
  		   FLOOR(1.0 * (price - min_price) / (1.0 * range_price / bucket_num)) + 1 AS bucket 
    FROM purchase_detail_log, stats
  
)

SELECT bucket,
	   --計算階層的上限與下限
	   min_price + bucket_range * (bucket - 1) AS lower_limit,
       min_price + bucket_range * bucket AS upper_limit,
       --計算次數
       COUNT(price) AS num_purchase,
       --計算各階層的合計金額
       SUM(price) AS total_amount
FROM purchase_log_with_bucket
GROUP BY bucket, 
		 min_price, 
         bucket_range
ORDER BY bucket
```