First commit, 已上架的電子書
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
根據 20241226-南港meeting
|
||||
BI 正航包 的資料結構
|
||||
|
||||
|
||||
《建立通用 DW 及 DashBoard》
|
||||
新建立下列 DW,這是通用的 DW,任何現有的 ERP 都可以透過 ETL 將資料寫入,然後就可以配合已經設計好的 DashBoard 顯示
|
||||
讓 BI 立刻無縫導入,提高客戶的使用意願
|
||||
|
||||
Michael 20250530
|
||||
*/
|
||||
|
||||
正航包功能列表
|
||||
0.前言:基本上是由上到下、由大到小的分析
|
||||
a.先全公司不細分的總合計額,y-ray=銷售額及毛利 x-ray=年月
|
||||
b.依 BU、通路、地區或產品類別為單一查詢條件(細分),y-ray=銷售額及毛利 x-ray=年月
|
||||
c.依 BU、通路、地區或產品類別為主視角(單一細分),y-ray=多BU(不超過10個)的銷售額(或毛利)擇一 x-ray=年月
|
||||
d.Widge 要準備多折線圖(組合)及 Map 及 環狀圖
|
||||
e.Dashboard 要研究如何 Drill Down
|
||||
f.如果可以,應該加入樞紐分析和資料列表
|
||||
g.傳統簡易型的上方圖表+下方 Table 資料的也可以寫寫
|
||||
|
||||
總結:
|
||||
Dashboard 應以 3-5 個重點圖表 為核心,確保簡潔且易於理解,次要資訊可透過互動功能呈現。
|
||||
|
||||
BISR00 趨勢分析
|
||||
BISR01 公司年度趨勢分析 Filter=年 y-ray=銷售額及毛利 x-ray=年月
|
||||
BISR11 公司年度銷售分析 Filter=年 y-ray=銷售額及毛利 x-ray=年月
|
||||
BISR03 BU各月業績達成率總表
|
||||
|
||||
BISR10 銷售分析與預測 >> DashBoard 的多圖趨勢分析
|
||||
BISR11 客戶類別年度銷售趨勢分析 Filter=年+客戶類別 y-ray=多筆客戶類別+銷售額 x-ray=年月
|
||||
BISR12 BU 年度銷售分析 Filter=年+BU y-ray=多筆BU+銷售額 x-ray=年月
|
||||
BISR13 地區年度銷售分析 Filter=年+地區 y-ray=多筆地區+銷售額 x-ray=年月
|
||||
BISR14 商品類別銷售趨勢 Filter=年+商品類別 y-ray=多筆商品類別+銷售額 x-ray=年月
|
||||
BISR15 品牌銷售趨勢分析 Filter=年+商品 y-ray=多筆品牌+銷售額 x-ray=年月 >> 未指定就取前10
|
||||
|
||||
BISR20 營運效益分析 >> 傳統的上圖下數字的基本 BI 分析
|
||||
BISR11 客戶類別年度銷售趨勢分析 Filter=年+客戶類別 y-ray=多筆客戶類別+銷售額 x-ray=年月
|
||||
BISR12 BU 年度銷售趨勢分析 Filter=年+BU y-ray=多筆BU+銷售額 x-ray=年月
|
||||
BISR13 地區年度銷售趨勢分析 Filter=年+地區 y-ray=多筆地區+銷售額 x-ray=年月
|
||||
BISR14 商品類別銷售趨勢分析 Filter=年+商品類別 y-ray=多筆商品類別+銷售額 x-ray=年月
|
||||
BISR25 品牌銷售趨勢分析 Filter=年+商品 y-ray=多筆品牌+銷售額 x-ray=年月 >> 未指定就取前10
|
||||
|
||||
1 業績達成:BU別、業務別、TOP 20家客戶、產品別
|
||||
2 業績達成率:高階產品、高利基市場、Turnkey
|
||||
|
||||
BISR20 營運效率優化
|
||||
3 利潤同比成長:BU別、業務別、TOP 20家客戶、產品別
|
||||
4 利潤同比成長率:高階產品、Turnkey
|
||||
|
||||
BISR30 市場與競爭分析
|
||||
5 新客戶開發達成:新客數、開發達成率
|
||||
|
||||
BISR40 客戶行為分析
|
||||
6 客戶黏著度:客戶類別、挽回數、流失數、下單客數
|
||||
7 客戶流失率:新舊客數、期間內下單客數、流失率
|
||||
|
||||
BISR50 財務與風險分析
|
||||
|
||||
BISR60 供應鏈及庫存分析
|
||||
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,438 @@
|
||||
/*
|
||||
根據 20241226-南港meeting
|
||||
BI 正航包 的資料結構
|
||||
|
||||
|
||||
《建立通用 DW 及 DashBoard》
|
||||
新建立下列 DW,這是通用的 DW,任何現有的 ERP 都可以透過 ETL 將資料寫入,然後就可以配合已經設計好的 DashBoard 顯示
|
||||
讓 BI 立刻無縫導入,提高客戶的使用意願
|
||||
|
||||
???
|
||||
alter table dw_product_sales_statistics add esti_sales_amount decimal(18,2)
|
||||
alter table dw_product_sales_statistics add esti_sales_qty decimal(10,2)
|
||||
alter table dw_product_sales_statistics add esti_sales_profit decimal(18,2)
|
||||
|
||||
Michael 20250530
|
||||
*/
|
||||
|
||||
-- 全公司統計
|
||||
create table dw_company_statistics (
|
||||
stats_year varchar(4),
|
||||
stats_yymm varchar(6) not null,
|
||||
number_of_quot int, -- 報價單數
|
||||
number_of_order int, -- 訂單數
|
||||
number_of_sales int, -- 出貨單數
|
||||
number_of_return int, -- 退貨單數
|
||||
sales_amount decimal(18,2), -- 總銷售金額
|
||||
sales_qty decimal(10,2), -- 總銷售數量
|
||||
item_cost decimal(18,2), -- 總銷售成本
|
||||
sales_profit decimal(18,2) -- 總銷售毛利
|
||||
primary key (stats_yymm)
|
||||
)
|
||||
|
||||
-- 產品銷售統計
|
||||
create table dw_product_sales_statistics (
|
||||
productid varchar(50) not null,
|
||||
productname nvarchar(100),
|
||||
productclassid varchar(10),
|
||||
productclassname nvarchar(100),
|
||||
-- new 新增品牌統計
|
||||
brand_id varchar(20),
|
||||
brand_name nvarchar(100),
|
||||
--
|
||||
stats_year varchar(4),
|
||||
stats_yymm varchar(6) not null,
|
||||
sales_amount decimal(18,2),
|
||||
sales_qty decimal(10,2),
|
||||
item_cost decimal(18,2),
|
||||
sales_profit decimal(18,2),
|
||||
-- 新增預估欄位(Estimate) > 計算達成率
|
||||
-- esti_sales_amount decimal(18,2),
|
||||
-- esti_sales_qty decimal(10,2),
|
||||
-- esti_sales_profit decimal(18,2),
|
||||
primary key (productid,stats_yymm)
|
||||
)
|
||||
|
||||
insert into dw_product_sales_statistics ()
|
||||
select * from dw_tmp_sales_data
|
||||
|
||||
-- 產品類別銷售統計
|
||||
-- 基本上應該是由【產品銷售統計】再次計算得來
|
||||
create table dw_productclass_sales_statistics (
|
||||
productclassid varchar(10),
|
||||
productclassname nvarchar(100),
|
||||
stats_year varchar(4),
|
||||
stats_yymm varchar(6) not null,
|
||||
sales_amount decimal(18,2),
|
||||
sales_qty decimal(10,2),
|
||||
item_cost decimal(18,2),
|
||||
sales_profit decimal(18,2),
|
||||
primary key (productclassid,stats_yymm)
|
||||
)
|
||||
|
||||
-- 品牌銷售統計(New)
|
||||
-- 基本上應該是由【產品銷售統計】再次計算得來
|
||||
create table dw_brand_sales_statistics (
|
||||
brand_id varchar(20),
|
||||
brand_name nvarchar(100),
|
||||
stats_year varchar(4),
|
||||
stats_yymm varchar(6) not null,
|
||||
sales_amount decimal(18,2),
|
||||
sales_qty decimal(10,2),
|
||||
item_cost decimal(18,2),
|
||||
sales_profit decimal(18,2),
|
||||
primary key (brand_id,stats_yymm)
|
||||
)
|
||||
|
||||
-- 客戶銷售統計
|
||||
create table dw_customer_sales_statistics (
|
||||
custid varchar(50) not null,
|
||||
corpname nvarchar(100),
|
||||
custclassid varchar(10),
|
||||
custclassname nvarchar(100),
|
||||
/*
|
||||
areaid varchar(10),
|
||||
areaname nvarchar(100),
|
||||
channelid varchar(10),
|
||||
channelname nvarchar(100),
|
||||
*/
|
||||
stats_year varchar(4),
|
||||
stats_yymm varchar(6) not null,
|
||||
sales_amount decimal(18,2),
|
||||
sales_qty decimal(10,2),
|
||||
item_cost decimal(18,2),
|
||||
sales_profit decimal(18,2),
|
||||
-- 應收帳款(每個月的一號計算前一個月的應收 TBD)
|
||||
ar decimal(18,2),
|
||||
primary key (custid,stats_yymm)
|
||||
)
|
||||
|
||||
-- 客戶類別銷售統計
|
||||
-- 基本上應該是由【客戶銷售統計】再次計算得來
|
||||
create table dw_customerclass_sales_statistics (
|
||||
custclassid varchar(10),
|
||||
custclassname nvarchar(100),
|
||||
stats_year varchar(4),
|
||||
stats_yymm varchar(6) not null,
|
||||
sales_amount decimal(18,2),
|
||||
sales_qty decimal(10,2),
|
||||
item_cost decimal(18,2),
|
||||
sales_profit decimal(18,2),
|
||||
-- 應收帳款(每個月的一號計算前一個月的應收 TBD)
|
||||
ar decimal(18,2),
|
||||
primary key (custclassid,stats_yymm)
|
||||
)
|
||||
|
||||
-- 區域銷售統計
|
||||
-- 基本上應該是由【出貨單加總統計】計算得來
|
||||
create table dw_region_sales_statistics (
|
||||
regionid varchar(10),
|
||||
regionname nvarchar(100),
|
||||
stats_year varchar(4),
|
||||
stats_yymm varchar(6) not null,
|
||||
sales_amount decimal(18,2),
|
||||
sales_qty decimal(10,2),
|
||||
item_cost decimal(18,2),
|
||||
sales_profit decimal(18,2),
|
||||
-- 應收帳款(每個月的一號計算前一個月的應收 TBD)
|
||||
ar decimal(18,2),
|
||||
primary key (regionid,stats_yymm)
|
||||
)
|
||||
|
||||
-- 通路銷售統計
|
||||
-- 基本上應該是由【出貨單加總統計】計算得來
|
||||
create table dw_channel_sales_statistics (
|
||||
channelid varchar(10),
|
||||
channelname nvarchar(100),
|
||||
stats_year varchar(4),
|
||||
stats_yymm varchar(6) not null,
|
||||
sales_amount decimal(18,2),
|
||||
sales_qty decimal(10,2),
|
||||
item_cost decimal(18,2),
|
||||
sales_profit decimal(18,2),
|
||||
-- 應收帳款(每個月的一號計算前一個月的應收 TBD)
|
||||
ar decimal(18,2),
|
||||
primary key (channelid,stats_yymm)
|
||||
)
|
||||
|
||||
-- BU 銷售統計
|
||||
-- BU 企業內部的一個業務單位或分支,通常具有獨立的運營、產品線或市場責任
|
||||
create table dw_bu_sales_statistics (
|
||||
buid varchar(50) not null,
|
||||
buname nvarchar(100),
|
||||
stats_year varchar(4),
|
||||
stats_yymm varchar(6) not null,
|
||||
sales_amount decimal(18,2),
|
||||
sales_qty decimal(10,2),
|
||||
item_cost decimal(18,2),
|
||||
sales_profit decimal(18,2),
|
||||
primary key (buid,stats_yymm)
|
||||
)
|
||||
|
||||
|
||||
-- 一些基礎的暫存資料
|
||||
-- 加入品牌及分類(new) + hotel define(Jack) Id+Name
|
||||
create table dw_tmp_data (
|
||||
id_type varchar(10) not null,
|
||||
id_no varchar(50) not null,
|
||||
id_name nvarchar(100),
|
||||
id_desc nvarchar(100),
|
||||
sales_price decimal(18,2),
|
||||
sales_qty decimal(10,2)
|
||||
primary key (id_type,id_no)
|
||||
)
|
||||
|
||||
|
||||
-- 其他銷售統計
|
||||
-- 其他銷售統計
|
||||
|
||||
-- DE-BI DJI 部分參考資料
|
||||
create table dw_tmp_sales_data (
|
||||
銷售日期 varchar(10),
|
||||
進銷碼 varchar(20),
|
||||
進銷碼名稱 nvarchar(100),
|
||||
銷售人員 varchar(50),
|
||||
數量 int,
|
||||
合計金額 int,
|
||||
未稅金額 int,
|
||||
後台成本 int,
|
||||
後台毛利 int,
|
||||
建議售價 int,
|
||||
分店簡稱 nvarchar(20),
|
||||
分店代碼 varchar(10),
|
||||
大分類 nvarchar(100),
|
||||
中分類 nvarchar(100),
|
||||
小分類 nvarchar(100),
|
||||
督導區域 nvarchar(100),
|
||||
週報 nvarchar(100),
|
||||
商品品牌 nvarchar(100)
|
||||
)
|
||||
|
||||
|
||||
-- 將資料寫入dw_product_sales_statistics (TBD)
|
||||
with d0 as
|
||||
(
|
||||
select
|
||||
進銷碼 productid,進銷碼名稱 productname,分店簡稱,週報,商品品牌 as brand,商品品牌,substring(銷售日期,1,4) sdate,substring(銷售日期,1,6) mdate,合計金額,數量,後台成本,後台毛利
|
||||
from dw_tmp_sales_data
|
||||
), d1 as
|
||||
(
|
||||
select productid,productname,分店簡稱,週報,brand,商品品牌,sdate,mdate,sum(合計金額) AMT1,sum(數量) AMT2,sum(後台成本) AMT3,sum(後台毛利) AMT4
|
||||
from d0
|
||||
group by productid,productname,分店簡稱,週報,brand,商品品牌,sdate,mdate
|
||||
)
|
||||
insert into dw_product_sales_statistics (productid,productname,productclassid,productclassname,brand_id,brand_name,stats_year,stats_yymm,sales_amount,sales_qty,item_cost,sales_profit)
|
||||
select * from d1
|
||||
|
||||
|
||||
/*
|
||||
1.先純手工編出 202301 的資料(盡量合理) >> 推算出 2023 及 2024 兩年的全部 24 個月的資料
|
||||
月營業額 10,000,000
|
||||
月銷量 1200
|
||||
成本 sales_amount * 65%
|
||||
2.合理的分配到 product 及 customer 上(類別透過計算)
|
||||
一樣都先設定 202301 為基準的參考月份
|
||||
|
||||
|
||||
|
||||
202302 >>> * 1.55
|
||||
202303 >>> * 0.8
|
||||
202304 >>> * 0.7
|
||||
202305 >>> * 0.92
|
||||
202306 >>> * 1.15
|
||||
202307 >>> * 1.2
|
||||
202308 >>> * 1.38
|
||||
202309 >>> * 1.12
|
||||
202310 >>> * 0.92
|
||||
202311 >>> * 0.98
|
||||
202312 >>> * 1.05
|
||||
|
||||
202401 >>> * 1.2
|
||||
202402 >>> * 1.62
|
||||
202403 >>> * 0.92
|
||||
202404 >>> * 0.88
|
||||
202405 >>> * 0.96
|
||||
202406 >>> * 1.09
|
||||
202407 >>> * 1.19
|
||||
202408 >>> * 1.33
|
||||
202409 >>> * 1.52
|
||||
202410 >>> * 0.88
|
||||
202411 >>> * 0.91
|
||||
202412 >>> * 1.2
|
||||
*/
|
||||
|
||||
/*
|
||||
MI 小米
|
||||
RedMI 紅米
|
||||
select * from dw_product_sales_statistics where brand_id is null
|
||||
|
||||
update dw_product_sales_statistics set brand_id = 'RedMI',brand_name='紅米'
|
||||
where productname like '%紅米%';
|
||||
|
||||
update dw_product_sales_statistics set brand_id = 'MI',brand_name='小米'
|
||||
where productname like '%小米%' and brand_id is null
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
以下是和 Hotel 有關的 Table
|
||||
*/
|
||||
|
||||
-- 加入 Hotel 的 Demo 資料集
|
||||
-- 業績預估
|
||||
create table dw_hotel_esti_data (
|
||||
hotel_id varchar(10) not null, -- hotel id
|
||||
hotel_name nvarchar(100),
|
||||
stats_year varchar(4), -- 統計年
|
||||
stats_yymm varchar(6) not null, -- 統計年月
|
||||
esti_month_amount int, -- 月預估營業額
|
||||
primary key (hotel_id,stats_yymm)
|
||||
)
|
||||
|
||||
-- 實際業績
|
||||
/*
|
||||
住房率 = (order_no / hotel_room_no) * 100
|
||||
平均房價 sum(sales_week_amount) / hotel_room_no
|
||||
達成率 = (sum(sales_week_amount) / esti_month_amount) * 100
|
||||
|
||||
*/
|
||||
create table dw_hotel_data (
|
||||
hotel_id varchar(10) not null, -- hotel id
|
||||
hotel_name nvarchar(100),
|
||||
hotel_room_no int, -- 房間數
|
||||
stats_year varchar(4), -- 統計年
|
||||
stats_yymm varchar(6) not null, -- 統計年月
|
||||
week_number int, -- 年度週數
|
||||
WeekStart date,
|
||||
WeekEnd date,
|
||||
order_no int, -- 訂房數
|
||||
sales_week_amount int, -- 週營業額
|
||||
primary key (hotel_id,stats_yymm,week_number)
|
||||
)
|
||||
|
||||
-- 實際業績的年月統計(sum from )
|
||||
-- 本 Table 可以用 View=v_dw_hotel_sum_data 完全代替 (除非資料會很大,否則不建議使用)
|
||||
/*
|
||||
delete from dw_hotel_sum_data where stats_year = '2025';
|
||||
|
||||
insert into dw_hotel_sum_data (hotel_id,hotel_name,stats_year,stats_yymm,month_amount)
|
||||
select hotel_id,hotel_name,stats_year,stats_yymm,sum(sales_week_amount) from dw_hotel_data
|
||||
where stats_year = '2025'
|
||||
group by hotel_id,hotel_name,stats_year,stats_yymm;
|
||||
*/
|
||||
create table dw_hotel_sum_data (
|
||||
hotel_id varchar(10) not null, -- hotel id
|
||||
hotel_name nvarchar(100),
|
||||
stats_year varchar(4), -- 統計年
|
||||
stats_yymm varchar(6) not null, -- 統計年月
|
||||
month_amount int, -- 月預估營業額
|
||||
primary key (hotel_id,stats_yymm)
|
||||
)
|
||||
|
||||
|
||||
-- 產生 hotel 的基本資料, 部分欄位要候補
|
||||
with week_data as
|
||||
(
|
||||
select min(WeekNumber)-1 min_week,max(WeekNumber) max_week from Year_WeekData where MonthNumber = 5
|
||||
)
|
||||
-- insert into dw_hotel_data (hotel_id,hotel_name,hotel_room_no,stats_year,stats_yymm,week_number,WeekStart,WeekEnd,order_no,sales_week_amount)
|
||||
select
|
||||
T.id_no,T.id_name,0,'2025','202505',
|
||||
--WD.min_week,WD.max_week,
|
||||
YW.WeekNumber,YW.StartDate,YW.EndDate,0,0
|
||||
from dw_tmp_data T
|
||||
left join week_data WD on 1=1
|
||||
left join Year_WeekData YW on 1=1
|
||||
where T.id_type = 'hotel'
|
||||
and YW.WeekNumber >= WD.min_week and YW.WeekNumber <= WD.max_week
|
||||
order by 3,1
|
||||
|
||||
-- 2025 1-6 月(Now Data)
|
||||
-- insert into dw_hotel_data (hotel_id,hotel_name,hotel_room_no,stats_year,stats_yymm,week_number,WeekStart,WeekEnd,order_no,sales_week_amount)
|
||||
select
|
||||
T.id_no,T.id_name,T.sales_qty,'2025',convert(varchar(4),YW.StartDate,112)+case when YW.MonthNumber < 10 then '0'+cast(YW.MonthNumber as varchar) else cast(YW.MonthNumber as varchar) end,
|
||||
YW.WeekNumber,YW.StartDate,YW.EndDate,
|
||||
--FLOOR(RAND(CHECKSUM(NEWID())) * (75 - 35 + 1)) + 35,
|
||||
round(T.sales_qty*7*((FLOOR(RAND(CHECKSUM(NEWID())) * (65 - 35 + 1)) + 25)/100),0),
|
||||
round(T.sales_qty*7*((FLOOR(RAND(CHECKSUM(NEWID())) * (65 - 35 + 1)) + 25)/100)*1800,0)
|
||||
from dw_tmp_data T
|
||||
-- left join week_data WD on 1=1
|
||||
left join Year_WeekData YW on 1=1
|
||||
where T.id_type = 'hotel'
|
||||
and YW.WeekNumber <=40
|
||||
order by 1,6;
|
||||
|
||||
/*
|
||||
達成率
|
||||
配合 metabase 元件,只能有一個數字
|
||||
H01-H07 各飯店-當月達成率
|
||||
*/
|
||||
select
|
||||
--H.hotel_id,H.hotel_name,H.stats_yymm,
|
||||
--(H.month_amount*1.0/E.esti_month_amount*1.0)*100,
|
||||
(H.month_amount*1.0 / (case when E.esti_month_amount = 0 then 1 else E.esti_month_amount end)) * 100 as pass_rate
|
||||
from dw_hotel_sum_data H
|
||||
left join dw_hotel_esti_data E on H.hotel_id = E.hotel_id and H.stats_yymm = E.stats_yymm
|
||||
where hotel_id = 'H01' and H.stats_yymm = convert(char(6), getdate(), 112)
|
||||
|
||||
|
||||
select
|
||||
H.hotel_id,H.hotel_name,H.stats_yymm,H.month_amount,E.esti_month_amount,
|
||||
(H.month_amount*1.0 / (case when E.esti_month_amount = 0 then 1 else E.esti_month_amount end)) * 100 as pass_rate
|
||||
from dw_hotel_sum_data H
|
||||
left join dw_hotel_esti_data E on H.hotel_id = E.hotel_id and H.stats_yymm = E.stats_yymm
|
||||
where H.stats_year = convert(char(4), getdate(), 112)
|
||||
|
||||
|
||||
-- 可以用這個 View 代替實體的 Table=dw_hotel_sum_data
|
||||
CREATE VIEW v_dw_hotel_sum_data AS
|
||||
SELECT
|
||||
hotel_id,
|
||||
hotel_name,
|
||||
stats_year, -- 統計年
|
||||
stats_yymm, -- 統計年月
|
||||
sum(sales_week_amount) month_amount -- 月預估營業額
|
||||
FROM dw_hotel_data H
|
||||
group by hotel_id,hotel_name,stats_yymm
|
||||
|
||||
|
||||
-- 樞紐分析(配合 Metabase 使用)
|
||||
CREATE VIEW v_hotel_monthly_pass_rate AS
|
||||
with hotel_data as
|
||||
(
|
||||
SELECT
|
||||
hotel_id,
|
||||
hotel_name,
|
||||
stats_yymm,
|
||||
sum(sales_week_amount) month_amount
|
||||
FROM dw_hotel_data H
|
||||
group by hotel_id,hotel_name,stats_yymm
|
||||
)
|
||||
select
|
||||
H.hotel_id,
|
||||
H.hotel_name,
|
||||
H.stats_yymm,
|
||||
H.month_amount,
|
||||
E.esti_month_amount,
|
||||
(H.month_amount * 1.0 / NULLIF(E.esti_month_amount, 0)) * 100 AS pass_rate
|
||||
from hotel_data H
|
||||
LEFT JOIN dw_hotel_esti_data E
|
||||
ON H.hotel_id = E.hotel_id AND H.stats_yymm = E.stats_yymm;
|
||||
|
||||
|
||||
|
||||
|
||||
-- 樞紐分析(配合 Metabase 使用) > 舊版(已不使用)
|
||||
CREATE VIEW v_hotel_monthly_pass_rate AS
|
||||
SELECT
|
||||
H.hotel_id,
|
||||
H.hotel_name,
|
||||
H.stats_yymm,
|
||||
H.month_amount,
|
||||
E.esti_month_amount,
|
||||
(H.month_amount * 1.0 / NULLIF(E.esti_month_amount, 0)) * 100 AS pass_rate
|
||||
FROM dw_hotel_sum_data H
|
||||
LEFT JOIN dw_hotel_esti_data E
|
||||
ON H.hotel_id = E.hotel_id AND H.stats_yymm = E.stats_yymm
|
||||
@@ -0,0 +1,130 @@
|
||||
這個 SQL Script 是針對 Jack 的飯店業 BI
|
||||
需要看到周變化,所以整理出來的 Script
|
||||
BI 一般是看趨勢,理論上不會看到這麼細,但是要做當然是可以的
|
||||
|
||||
|
||||
/*
|
||||
以年度共幾周為單位取日期區間(一年共 52 周)
|
||||
以下內容是 ChatGPT 的結果,令人驚豔
|
||||
|
||||
Michael 20250604
|
||||
*/
|
||||
|
||||
SET DATEFIRST 7; -- 設定週日為每週第一天
|
||||
|
||||
WITH Weeks AS (
|
||||
SELECT
|
||||
DATEADD(DAY, -(DATEPART(WEEKDAY, DATEFROMPARTS(2025, 1, 1)) - 1), DATEFROMPARTS(2025, 1, 1)) AS WeekStart
|
||||
UNION ALL
|
||||
SELECT
|
||||
DATEADD(WEEK, 1, WeekStart)
|
||||
FROM Weeks
|
||||
WHERE DATEADD(WEEK, 1, WeekStart) <= DATEFROMPARTS(2025, 12, 31)
|
||||
),
|
||||
WeeksWithMonth AS (
|
||||
SELECT
|
||||
ROW_NUMBER() OVER (ORDER BY WeekStart) AS WeekNumber,
|
||||
WeekStart,
|
||||
DATEADD(DAY, 6, WeekStart) AS EndDate,
|
||||
MONTH(WeekStart) AS MonthNumber,
|
||||
DATENAME(MONTH, WeekStart) AS MonthName,
|
||||
YEAR(WeekStart) AS YearNumber
|
||||
FROM Weeks
|
||||
WHERE YEAR(WeekStart) = 2025 OR YEAR(DATEADD(DAY, 6, WeekStart)) = 2025
|
||||
),
|
||||
WeeksWithMonthRank AS (
|
||||
SELECT *,
|
||||
ROW_NUMBER() OVER (PARTITION BY YearNumber, MonthNumber ORDER BY WeekStart) AS WeekOfMonth
|
||||
FROM WeeksWithMonth
|
||||
)
|
||||
SELECT
|
||||
WeekNumber,
|
||||
WeekStart AS StartDate,
|
||||
EndDate,
|
||||
MonthName,
|
||||
MonthNumber,
|
||||
WeekOfMonth -- ?? 當月第幾週
|
||||
-- into Year_WeekData
|
||||
FROM WeeksWithMonthRank
|
||||
ORDER BY StartDate
|
||||
OPTION (MAXRECURSION 100)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
以下的寫法會將跨月的周,拆成 2 筆
|
||||
目的是如果要以月為單位看第幾周,就用下面的語法
|
||||
*/
|
||||
|
||||
-- SET DATEFIRST 7; -- 設定週日為一週的第一天(星期日)
|
||||
SET DATEFIRST 1; -- 設定週一為一週的第一天(星期一)
|
||||
|
||||
-- 產生所有週的開始日
|
||||
WITH Weeks AS (
|
||||
SELECT
|
||||
DATEADD(DAY, -(DATEPART(WEEKDAY, DATEFROMPARTS(2025, 1, 1)) - 1), DATEFROMPARTS(2025, 1, 1)) AS WeekStart
|
||||
UNION ALL
|
||||
SELECT
|
||||
DATEADD(WEEK, 1, WeekStart)
|
||||
FROM Weeks
|
||||
WHERE DATEADD(WEEK, 1, WeekStart) <= DATEFROMPARTS(2025, 12, 31)
|
||||
),
|
||||
|
||||
-- 加上 WeekNumber(全年第幾週)
|
||||
WeeksWithNumber AS (
|
||||
SELECT
|
||||
ROW_NUMBER() OVER (ORDER BY WeekStart) AS WeekNumber,
|
||||
WeekStart,
|
||||
DATEADD(DAY, 6, WeekStart) AS WeekEnd
|
||||
FROM Weeks
|
||||
),
|
||||
|
||||
-- 將每週展開成7天
|
||||
DaysInWeek AS (
|
||||
SELECT
|
||||
W.WeekNumber,
|
||||
W.WeekStart,
|
||||
DATEADD(DAY, N.number, W.WeekStart) AS DayDate
|
||||
FROM WeeksWithNumber W
|
||||
JOIN master.dbo.spt_values N ON N.type = 'P' AND N.number BETWEEN 0 AND 6
|
||||
WHERE YEAR(DATEADD(DAY, N.number, W.WeekStart)) = 2025
|
||||
),
|
||||
|
||||
-- 拆分週中涉及的每個月份的起訖日
|
||||
WeekMonthSplit AS (
|
||||
SELECT
|
||||
WeekNumber,
|
||||
WeekStart,
|
||||
MONTH(DayDate) AS MonthNumber,
|
||||
DATENAME(MONTH, DayDate) AS MonthName,
|
||||
YEAR(DayDate) AS YearNumber,
|
||||
MIN(DayDate) AS StartDate,
|
||||
MAX(DayDate) AS EndDate
|
||||
FROM DaysInWeek
|
||||
GROUP BY WeekNumber, WeekStart, MONTH(DayDate), DATENAME(MONTH, DayDate), YEAR(DayDate)
|
||||
),
|
||||
|
||||
-- 加上「當月第幾週」
|
||||
FinalResult AS (
|
||||
SELECT *,
|
||||
ROW_NUMBER() OVER (PARTITION BY YearNumber, MonthNumber ORDER BY StartDate) AS WeekOfMonth
|
||||
FROM WeekMonthSplit
|
||||
)
|
||||
|
||||
-- 輸出最終結果
|
||||
SELECT
|
||||
ROW_NUMBER() OVER (ORDER BY StartDate) AS RecordID,
|
||||
WeekNumber,
|
||||
WeekStart,
|
||||
StartDate,
|
||||
EndDate,
|
||||
MonthName,
|
||||
MonthNumber,
|
||||
WeekOfMonth
|
||||
-- into Year_WeekData
|
||||
FROM FinalResult
|
||||
ORDER BY StartDate
|
||||
OPTION (MAXRECURSION 100)
|
||||
Reference in New Issue
Block a user