Email Yêu Cầu Từ Leader
Team đang có 3 matrix riêng lẻ:
- Matrix theo Fiscal Week → chỉ hiển thị Last 5 Weeks
- Matrix theo Fiscal Period → chỉ hiển thị Last 2 Periods
- Matrix theo Date → chỉ hiển thị Last 30 Days
Anh muốn gộp lại thành 1 matrix duy nhất và dùng slicer để người dùng chọn trục thời gian. Yêu cầu:
- Có slicer chọn Time grain: Date / FiscalWeek / FiscalPeriod.
- Có slicer chọn N (Last N) và danh sách N phải đổi theo grain:
- Date: cho phép 1 – 60
- Week: cho phép 1 – 12
- Period: cho phép 1 – 6
- Có label động trên report: “Showing: Last N days/weeks/periods”
- Outout anh mong muốn
Bước 1: Relationship
- DimDate[DateKey] (1) → FactGoodsIssue[DateKey] (*)
- DimCustomer[CustomerKey] (1) → FactGoodsIssue[CustomerKey] (*)
- DimStatus[StatusKey] (1) → FactGoodsIssue[StatusKey] (*)
Bước 2: Sort để Week/Period hiển thị đúng thứ tự
- Chọn DimDate[FiscalWeek] → Sort by column → DimDate[WeekIndex]
- DimDate[FiscalPeriod] → Sort by column → DimDate[PeriodIndex]
Bước 3:
Goods Issue =
SUM ( FactGoodsIssue[Goods Issue] )
Bước 4: Tạo Field Parameter để switch cột
- 4.1. Vào Modeling → New parameter → Fields
- 4.2. Chọn 3 field từ DimDate (nhớ chọn từ DimDate, không chọn từ Fact):
- DimDate[Date]
- DimDate[FiscalWeek]
- DimDate[FiscalPeriod]
- 4.3. Đặt tên: Time Axis
- 4.4. Tick “Add slicer to this page”
Field Parameter hoạt động như thế nào?
Time Axis = {
("Date", NAMEOF('DimDate'[Date]), 0),
▲ ▲ ▲
│ │ │
│ │ └── Thứ tự (Order)
│ │
│ └── NAMEOF(): Lấy tên đầy đủ của field
│ (để Power BI biết tham chiếu đến đâu)
│
└── Label hiển thị cho user
}
Bước 5: Tạo table GrainConfig để định nghĩa default & giới hạn N theo grain
Vào Modeling → New table
GrainConfig =
DATATABLE( -- Tạo bảng "cứng" trong model, chỉ dùng cho bảng TĨNH, ít dòng
-- Phù hợp cho: config tables, mapping tables, lookup tables
"Grain", STRING, -- Khai báo cột 1: tên + kiểu dữ liệu
"GrainOrder", INTEGER,
"WindowLabel", STRING,
"WindowSize", INTEGER, -- Default khi user chưa chọn N
"MaxN", INTEGER, -- Giới hạn danh sách N hợp lệ theo grain
{ -- Bắt đầu dữ liệu (các dòng)
{"Date", 0, "Last 30 Days", 30, 60}, -- Dòng 1
{"FiscalWeek", 1, "Last 5 Weeks", 5, 12},
{"FiscalPeriod",2, "Last 2 Periods", 2, 6}
})
Tại sao cần bảng GrainConfig?
Bước 6: Tạo table N Options để slicer N tự đổi theo grain
Vào Modeling → New table
N Options =
GENERATE( -- Hàm "nhân" 2 bảng với nhau
GrainConfig, -- Bảng 1: lấy từ GrainConfig (3 dòng)
SELECTCOLUMNS(
GENERATESERIES( -- Tạo dãy số từ 1 đến MaxN
1, -- Bắt đầu từ 1
GrainConfig[MaxN], -- Kết thúc ở MaxN (60, 12, hoặc 6)
1 -- Bước nhảy = 1
),
"N", [Value] -- Đổi tên cột thành "N"
)
)
Tại sao cần bảng N Options?
- Khi user chọn Date → Slicer N hiện: 1, 2, 3, … 60
- Khi user chọn Week → Slicer N hiện: 1, 2, 3, … 12
- Khi user chọn Period → Slicer N hiện: 1, 2, 3, … 6
- Nếu dùng 1 bảng cố định [1-60] → Period vẫn hiện 60 giá trị (sai UX!)
- Giải pháp: Tạo table N Options chứa tất cả các giá trị của N
- Mỗi dòng = 1 cặp (Grain, N)
- Dùng relationship để filter: chọn grain nào → chỉ hiện N của grain đó
Kiến thức DAX: Hàm GENERATE() + GENERATESERIES() trực quan
KHI user chọn → Slicer N sẽ tự lọc theo relationship
Tạo relationship để slicer N tự lọc theo grain
- Time Axis'[Time Axis Order] → GrainConfig[GrainOrder]
- GrainConfig[GrainOrder] → N Options[GrainOrder]
Bước 7: DAX “Last N”
-- Measure lấy N
Selected N =
VAR NFromSlicer = SELECTEDVALUE('N Options'[N])
VAR DefaultN = MAX(GrainConfig[WindowSize])
RETURN COALESCE(NFromSlicer, DefaultN)
Goods Issue (Last N Visible) =
VAR N = [Selected N]
VAR MaxDate =
CALCULATE ( MAX ( DimDate[Date] ), ALLSELECTED ( DimDate ) )
VAR MaxWeekIndex =
CALCULATE ( MAX ( DimDate[WeekIndex] ), ALLSELECTED ( DimDate ) )
VAR MaxPeriodIndex =
CALCULATE ( MAX ( DimDate[PeriodIndex] ), ALLSELECTED ( DimDate ) )
VAR InWindow =
SWITCH (
TRUE (),
ISINSCOPE ( DimDate[Date] ),
MAX ( DimDate[Date] ) >= MaxDate - ( N - 1 ),
ISINSCOPE ( DimDate[FiscalWeek] ),
MAX ( DimDate[WeekIndex] ) >= MaxWeekIndex - ( N - 1 ),
ISINSCOPE ( DimDate[FiscalPeriod] ),
MAX ( DimDate[PeriodIndex] ) >= MaxPeriodIndex - ( N - 1 ),
TRUE()
)
RETURN
IF ( InWindow, [Goods Issue], BLANK() )
BLANK() làm matrix tự ẩn cột
Tại sao dùng ISINSCOPE thay vì SELECTEDVALUE?
Vấn đề: Làm sao biết user đang xem theo Date, Week, hay Period?
VAR Grain = SELECTEDVALUE(‘Time Axis'[Time Axis]) -> Đọc từ slicer (LỖI) -> Vì: Field Parameter là “composite” (chứa nhiều field)
Dùng ISINSCOPE
- ISINSCOPE(DimDate[Date]) = TRUE nếu Date đang được GROUP BY
- ISINSCOPE(DimDate[FiscalWeek]) = TRUE nếu Week đang được GROUP BY
- → Không đọc từ slicer, mà kiểm tra Matrix đang group theo field nào -> Không bị composite key issues
Kiến thức DAX: Hàm ISINSCOPE() trực quan
Kiến thức DAX: Hàm COALESCE() và SWITCH(TRUE())
COALESCE(value1, value2, …) = Trả giá trị đầu tiên KHÔNG phải BLANK
Selected N =
VAR NFromSlicer = SELECTEDVALUE('N Options'[N]) ← Có thể BLANK
VAR DefaultN = MAX(GrainConfig[WindowSize]) ← Fallback
RETURN COALESCE(NFromSlicer, DefaultN)
→ Nếu user không chọn N → dùng DefaultN (30, 5, hoặc 2)
SWITCH(TRUE(), …) = Pattern “if – elseif – else” trong DAX
SWITCH(
TRUE(), ← Kiểm tra điều kiện nào TRUE
ISINSCOPE(DimDate[Date]), ..., ← Nếu Date → chạy logic Date
ISINSCOPE(DimDate[Week]), ..., ← Nếu Week → chạy logic Week
TRUE() ← Default (else)
)
Kiểm tra từ trên xuống, dừng ở điều kiện TRUE đầu tiên
Bước 8: Label “Showing: Last N days/weeks/periods”
Label - Window =
VAR Grain = MAX(GrainConfig[Grain]) -- Lấy grain đang được chọn
VAR N = [Selected N] -- Lấy N từ slicer/default
VAR Unit =
SWITCH(
Grain,
"Date", "days", -- Date → hiện "days"
"FiscalWeek", "weeks", -- Week → hiện "weeks"
"FiscalPeriod", "periods", -- Period → hiện "periods"
"days" -- Default
)
RETURN
"Showing: Last " & N & " " & Unit -- Ghép chuỗi
Nếu bạn thích vừa học kiến thức vừa thực chiến qua Challenges như thế này thì có thể đăng ký khóa học Power BI Mastery Thực Chiến . Để đăng ký khóa học, bạn có thể inbox mình Tại Đây.

Leave a Comment