###### 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
```