سناریوی پروژه
یک کارخانهی فرش ماشینی در کاشان دوازده نمایندهی فروش در استانهای مختلف دارد. نرمافزار حسابداری هر ماه یک فایل CSV از فاکتورها میدهد و مدیرعامل هر شنبه میپرسد: «این ماه چقدر فروختیم، کدام طرح و کدام استان، و نسبت به ماه قبل چطور؟». هدف: فایلی که هر ماه فقط با انداختن CSV جدید در پوشه و یک Refresh All بهروز شود. این پروژه فصلهای ۱ تا ۷ را به هم وصل میکند.
ورودیها
| فایل یا جدول | ستونها | منبع |
|---|---|---|
| Sales\1403-01.csv و … | Date, InvoiceNo, Customer, Rep, Design, Reed, Area, Amount | خروجی ماهانهی حسابداری |
| Products.xlsx | Design, Collection, Density, ListPrice | واحد تولید |
| جدول Reps | Rep, Province, Manager | واحد فروش، در همین فایل |
| جدول Cal | Miladi, Shamsi, Year, Month, MonthName, YM, MonthIdx | جدول تقویم فصل ۱ |
گام ۱: Power Query
- Query Sales: From Folder روی پوشهی Sales با کد M فصل ۵ (Encoding 65001، اصلاح ی و ک، تعیین نوع داده با Culture).
- Query Products و Reps: ستونهای کلید (Design و Rep) را Trim و اصلاح حروف کنید؛ «طرح افشان» با ی عربی در یک طرف و ی فارسی در طرف دیگر، رابطه را بیصدا میشکند.
- کنترل کیفیت: یک Query با Merge از نوع Left Anti بین Sales و Products بسازید که طرحهای ناشناخته را نشان دهد. این Query باید همیشه خالی باشد.
- همه را با Close & Load To ← Only Create Connection و تیک Add this data to the Data Model بارگذاری کنید.
// Query: Sales_Missing_Design (باید صفر سطر داشته باشد)
let
J = Table.NestedJoin(Sales, {"Design"}, Products, {"Design"}, "P", JoinKind.LeftAnti),
R = Table.Distinct(Table.SelectColumns(J, {"Design"}))
in
R
گام ۲: رابطهها و Measureها
Data ← Relationships (یا Power Pivot ← Diagram View): Sales[Date] → Cal[Miladi]، Sales[Design] → Products[Design] و Sales[Rep] → Reps[Rep]. جدول فروش در مرکز و جدولهای بُعد دورش؛ همان «مدل ستارهای» که هر ابزار BI انتظارش را دارد.
Sales Amount := SUM ( Sales[Amount] )
Area m2 := SUM ( Sales[Area] )
Price per m2 := DIVIDE ( [Sales Amount], [Area m2] )
Customers := DISTINCTCOUNT ( Sales[Customer] )
Invoices := DISTINCTCOUNT ( Sales[InvoiceNo] )
-- ماه قبلِ شمسی با MonthIdx (توابع Time Intelligence میلادیاند)
Prev Month Sales :=
VAR cur = MAX ( Cal[MonthIdx] )
RETURN CALCULATE ( [Sales Amount], ALL ( Cal ), Cal[MonthIdx] = cur - 1 )
MoM % := DIVIDE ( [Sales Amount] - [Prev Month Sales], [Prev Month Sales] )
ستون MonthIdx در جدول تقویم برابر Year*12+Month است؛ عددی پیوسته که میداند ماه قبلِ فروردین ۱۴۰۴، اسفند ۱۴۰۳ است. توابعی مثل PREVIOUSMONTH و SAMEPERIODLASTYEAR بر اساس ماه میلادی کار میکنند و در گزارش شمسی عدد غلط اما «معقولنما» میدهند؛ خطرناکترین نوع خطا.
گام ۳: Pivotهای محاسبه
در شیت Calc از Data Model سه Pivot بسازید: (۱) YM در سطرها با Sales Amount و Price per m2؛ (۲) Province با Sales Amount؛ (۳) Design با Value Filters ← Top 10. چیدمان را Tabular کنید و سرستونها را کوتاه. کارتها را در درس بعد مستقیم از مدل با CUBEVALUE میسازیم.
نکتههایی که کمتر کسی میداند
- نام Queryها، جدولها و ستونهای مدل را لاتین و بدون فاصله بگذارید؛ DAX با نام فارسی هم کار میکند، اما فرمولی که نیمی RTL و نیمی LTR است در نوار فرمول تقریباً ناخواناست.
- در Power Pivot ستون MonthName را با Sort by Column بر اساس Month مرتب کنید؛ وگرنه ماههای فارسی در Pivot الفبایی چیده میشوند (آبان، آذر، اردیبهشت…).
- اگر رابطه ساخته نمیشود و پیام many-to-many میآید، جدول بُعد کلید تکراری دارد. پیش از Remove Duplicates بفهمید چرا تکراری است؛ معمولاً یک طرح با دو قیمت ثبت شده است.
- Queryهای میانی را Only Create Connection نگه دارید؛ بارگذاری هر Query در شیت حجم فایل و زمان Refresh را بیدلیل بالا میبرد.
- مسیر پوشه را در یک سلول نامدار (pPath) بگذارید و در M با
Excel.CurrentWorkbook(){[Name="pPath"]}[Content]{0}[Column1]بخوانید؛ با جابهجایی پوشه یا تحویل فایل به همکار، فقط یک سلول عوض میشود.