439 lines
12 KiB
Plaintext
439 lines
12 KiB
Plaintext
/*
|
|
根據 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
|