Wadi Market analytics mart
Wadi Market (fictional) · 7 tables · 65,785 rows · version 1
A business-intelligence star schema: a date dimension with Saudi weekends, fiscal years and retail seasons, customer, product and channel dimensions, and three fact tables (order lines, web/app sessions and monthly marketing spend). The customer dimension keeps history (a slowly changing dimension), so a customer who moved city has two rows. Ideal for GROUP BY reporting, ROLLUP/CUBE, window functions, period-over-period comparisons and funnel analysis. Amounts are in SAR. The mart is simulated separately from the Wadi Market operational database, so its totals do not reconcile with the shop dataset.
The documentation is open to everyone. Querying this dataset in the playground is included with Formula Quest membership; lessons that use it follow their own access.
Relationships
Sample queries
SELECT d.year, d.month, d.month_name,
sum(f.net_amount) AS net_sales
FROM fact_sales AS f
JOIN dim_date AS d ON d.date_key = f.date_key
GROUP BY d.year, d.month, d.month_name
ORDER BY d.year, d.month;SELECT p.category,
sum(f.net_amount) AS net_sales,
sum(f.net_amount - f.cost_amount) AS gross_margin
FROM fact_sales AS f
JOIN dim_product AS p ON p.product_key = f.product_key
GROUP BY p.category
ORDER BY net_sales DESC;SELECT c.region, d.year, sum(f.net_amount) AS net_sales
FROM fact_sales AS f
JOIN dim_customer AS c ON c.customer_key = f.customer_key
JOIN dim_date AS d ON d.date_key = f.date_key
WHERE c.customer_key <> 0
GROUP BY c.region, d.year
ORDER BY c.region, d.year;SELECT ch.channel_name,
count(*) AS sessions,
avg(s.reached_product_page::int) AS product_page_rate,
avg(s.added_to_cart::int) AS cart_rate,
avg(s.purchased::int) AS conversion_rate
FROM fact_web_sessions AS s
JOIN dim_channel AS ch ON ch.channel_key = s.channel_key
GROUP BY ch.channel_name;SELECT d.year, d.quarter,
sum(m.spend_amount) AS spend,
sum(m.budget_amount) AS budget
FROM fact_marketing_spend AS m
JOIN dim_date AS d ON d.date_key = m.month_key
GROUP BY d.year, d.quarter
ORDER BY d.year, d.quarter;Data dictionary
dim_date
1,096 rows · primary key (date_key)Calendar dimension: one row per day from 2023-01-01 to 2025-12-31, with Saudi weekends, fiscal periods and retail seasons.
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| date_key | integer | no | PK | Date as a number in YYYYMMDD form, e.g. 20250314. Used as the foreign key in fact tables. |
| full_date | date | no | unique | The calendar date. |
| year | smallint | no | Calendar year. | |
| quarter | smallint | no | Calendar quarter (1–4). | |
| month | smallint | no | Month number (1–12). | |
| month_name | text | no | Month name in English, e.g. March. | |
| month_start | date | no | First day of the month (handy for monthly grouping and for joining monthly facts). | |
| iso_week | smallint | no | ISO week number (weeks start on Monday; early January can belong to the previous year's last week). | |
| day_of_month | smallint | no | Day of the month (1–31). | |
| day_of_week | smallint | no | Day of the week, 1 = Sunday … 7 = Saturday (the Saudi working week starts on Sunday). | |
| day_name | text | no | Day name in English, e.g. Friday. | |
| is_weekend | boolean | no | TRUE on Friday and Saturday (the weekend in Saudi Arabia). | |
| fiscal_year | smallint | no | Wadi Market's fiscal year, which runs 1 April – 31 March and is named after the year it ends in. | |
| fiscal_quarter | smallint | no | Fiscal quarter (Q1 = April–June). | |
| season | text | no | Retail season: Ramadan, Eid al-Fitr, Eid al-Adha, White Friday, National Day, Founding Day, Summer or Regular. | |
| is_ramadan | boolean | no | TRUE during the month of Ramadan. | |
| is_holiday | boolean | no | TRUE on Saudi public holidays (Founding Day, Eid holidays, National Day). | |
| holiday_name | text | yes | Name of the public holiday. NULL on ordinary days. |
dim_customer
1,040 rows · primary key (customer_key)Customer dimension with history (slowly changing dimension type 2): a new row is added when a customer moves city. customer_key 0 is the 'Guest checkout' member for orders without an account.
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| customer_key | integer | no | PK | Surrogate key for one version of a customer. Fact tables join on this. 0 = Guest checkout. |
| customer_id | integer | yes | Business (natural) key from the operational system; the same for every version of a customer. NULL for the guest member. | |
| full_name | text | no | Customer's name. | |
| segment | text | no | consumer, business, or guest (the Guest checkout member). | |
| city | text | yes | City the customer lived in while this version was valid. NULL for the guest member. | |
| region | text | yes | Region of that city (Central, Eastern, Western, Northern, Southern). NULL for the guest member. | |
| signup_date | date | yes | Date the customer first registered (same on every version). NULL for the guest member. | |
| valid_from | date | no | First day this version was valid. | |
| valid_to | date | no | Last day this version was valid; 9999-12-31 for the current version. | |
| is_current | boolean | no | TRUE for the customer's current version. |
dim_product
61 rows · primary key (product_key)Product dimension, flattened: each product carries its department (category) and lowest-level category (subcategory).
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| product_key | integer | no | PK | Surrogate key (starts at 1001). Fact tables join on this. |
| product_id | integer | no | unique | Natural key from the operational system. |
| sku | text | no | unique | Stock-keeping unit code, e.g. WM-ELE-1001. |
| product_name | text | no | Product name. | |
| category | text | no | Top-level department, e.g. Electronics. | |
| subcategory | text | no | Lowest-level category, e.g. Headphones. | |
| brand | text | no | Brand name; 'Unbranded' when the product has no brand. | |
| list_price | numeric(12,2) | no | Current list price in SAR. | |
| is_discontinued | boolean | no | TRUE if the product is no longer sold. |
dim_channel
4 rows · primary key (channel_key)Sales channels.
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| channel_key | integer | no | PK | Surrogate key for the channel. |
| channel_name | text | no | unique | Web, App, Marketplace or Social Commerce. |
| channel_type | text | no | owned (our own website/app/social shop) or partner (a third-party marketplace). | |
| has_session_tracking | boolean | no | TRUE if sessions on this channel are recorded in fact_web_sessions. | |
| launched_on | date | no | Date the channel started selling. |
fact_sales
25,153 rows · primary key (order_id, line_no)Sales fact table. Grain: one order line (one product in one order). Cancelled orders are not loaded.
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| order_id | integer | no | PK | Order number (a degenerate dimension: there is no order dimension table). |
| line_no | smallint | no | PK | Line number within the order. |
| date_key | integer | no | dim_date.date_key | Order date (YYYYMMDD). |
| customer_key | integer | no | dim_customer.customer_key | Customer version valid on the order date; 0 = Guest checkout. |
| product_key | integer | no | dim_product.product_key | Product sold. |
| channel_key | integer | no | dim_channel.channel_key | Channel the order came through. |
| quantity | integer | no | Units sold. | |
| gross_amount | numeric(12,2) | no | Quantity × list price at the time, in SAR, before discounts. | |
| discount_amount | numeric(12,2) | no | Promotional discount on the line in SAR. | |
| net_amount | numeric(12,2) | no | gross_amount − discount_amount: the revenue for the line in SAR. | |
| cost_amount | numeric(12,2) | yes | Cost of the goods sold on this line in SAR. NULL when the product's cost was not recorded. | |
| is_returned | boolean | no | TRUE if the line was later returned and refunded. |
fact_web_sessions
38,164 rows · primary key (session_id)Website, app and social-shop sessions with funnel flags. Grain: one visit. Marketplace orders happen on the partner's site and have no sessions here. Funnel steps are cumulative.
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| session_id | bigint | no | PK | Unique session number. |
| date_key | integer | no | dim_date.date_key | Day the session started (YYYYMMDD). |
| channel_key | integer | no | dim_channel.channel_key | Web, App or Social Commerce. |
| customer_key | integer | yes | dim_customer.customer_key | Logged-in customer version. NULL for anonymous visitors. |
| device | text | no | mobile, desktop or tablet. | |
| traffic_source | text | no | How the visitor arrived: organic, direct, paid_search, social, email or referral. | |
| reached_product_page | boolean | no | TRUE if the visitor viewed at least one product page. | |
| added_to_cart | boolean | no | TRUE if something was added to the cart. | |
| started_checkout | boolean | no | TRUE if the visitor started checkout. | |
| purchased | boolean | no | TRUE if the session ended in an order. | |
| order_id | integer | yes | The order placed in this session (matches fact_sales.order_id). NULL when nothing was bought. |
fact_marketing_spend
267 rows · primary key (spend_id)Monthly marketing spend and budget. Grain: one month × channel × campaign type. Months without activity have no row.
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| spend_id | integer | no | PK | Unique row number. |
| month_key | integer | no | dim_date.date_key | First day of the month the spend covers (YYYYMMDD, e.g. 20250301). |
| channel_key | integer | no | dim_channel.channel_key | Channel the campaign promoted. |
| campaign_type | text | no | paid_search, display, email, influencer, app_install, paid_social or sponsored_listings. | |
| spend_amount | numeric(12,2) | no | Actual spend in SAR. | |
| budget_amount | numeric(12,2) | no | Planned budget in SAR. |