Sahra Logistics warehousing and transport
Sahra Logistics (fictional) · 12 tables · 92,456 rows · version 1
Two years (2024–2025) of logistics operations. Stock side: suppliers, products, purchase orders and their lines, an inventory movement ledger (opening balances, receipts, monthly outbound totals and adjustments) and month-end inventory snapshots. Transport side: customers, carriers, routes, about 12,000 shipments and their scan events. Built for operations analytics: on-time delivery, carrier performance and seasonality, stock levels, reorder alerts and supplier lead times. Amounts are in SAR.
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 c.carrier_name, c.mode,
count(*) AS delivered,
round(100.0 * count(*) FILTER (WHERE s.delivered_at::date <= s.promised_date) / count(*), 1) AS on_time_pct
FROM shipments s
JOIN carriers c ON c.carrier_id = s.carrier_id
WHERE s.status = 'delivered'
GROUP BY c.carrier_name, c.mode
ORDER BY on_time_pct DESC;SELECT status, count(*) AS shipments, count(*) FILTER (WHERE delivered_at IS NULL) AS without_delivery_time
FROM shipments
GROUP BY status
ORDER BY shipments DESC;SELECT w.warehouse_code, p.sku, p.product_name, i.on_hand, i.allocated, p.reorder_level
FROM inventory_snapshots i
JOIN products p ON p.product_id = i.product_id
JOIN warehouses w ON w.warehouse_id = i.warehouse_id
WHERE i.snapshot_date = DATE '2025-12-31'
AND p.is_active
AND i.on_hand - i.allocated < p.reorder_level
ORDER BY i.on_hand - i.allocated - p.reorder_level;SELECT warehouse_id, product_id, sum(quantity) AS on_hand
FROM inventory_movements
WHERE movement_date <= DATE '2025-06-30'
GROUP BY warehouse_id, product_id
ORDER BY warehouse_id, product_id
LIMIT 20;SELECT su.supplier_name,
count(*) AS received_orders,
round(avg(po.received_on - po.ordered_on), 1) AS avg_lead_days,
count(*) FILTER (WHERE po.received_on > po.expected_on) AS late_orders
FROM purchase_orders po
JOIN suppliers su ON su.supplier_id = po.supplier_id
WHERE po.received_on IS NOT NULL
GROUP BY su.supplier_name
ORDER BY late_orders DESC;Data dictionary
warehouses
6 rows · primary key (warehouse_id)Warehouses / distribution centres.
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| warehouse_id | integer | no | PK | Unique warehouse number. |
| warehouse_code | text | no | unique | Short code (e.g. RUH1). |
| warehouse_name | text | no | Name. | |
| city | text | no | City (the origin city of its routes). | |
| capacity_pallets | integer | no | Storage capacity in pallet positions. | |
| opened_on | date | no | Opening date (Riyadh South opened during the data period). |
suppliers
20 rows · primary key (supplier_id)Suppliers the company buys stock from.
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| supplier_id | integer | no | PK | Unique supplier number. |
| supplier_name | text | no | unique | Name (fictional). |
| country | char(2) | no | ISO country code. | |
| city | text | no | City. | |
| lead_time_days | integer | no | Contracted days from order to delivery. |
products
60 rows · primary key (product_id)Stock-keeping units (SKUs). unit_cost is the current standard cost.
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| product_id | integer | no | PK | Unique product number. |
| sku | text | no | unique | Stock-keeping unit code. |
| product_name | text | no | Product name (pack size included). | |
| category | text | no | Product category. | |
| supplier_id | integer | no | suppliers.supplier_id | Usual supplier. |
| unit_weight_kg | numeric(6,3) | no | Weight of one unit in kg. | |
| unit_cost | numeric(12,2) | no | Current standard cost per unit in SAR. | |
| reorder_level | integer | no | Reorder when available stock (on_hand − allocated) falls below this, per warehouse. | |
| is_active | boolean | no | FALSE for discontinued products (no longer reordered). |
customers
180 rows · primary key (customer_id)Business customers receiving shipments.
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| customer_id | integer | no | PK | Unique customer number. |
| customer_name | text | no | Company name (fictional). | |
| segment | text | no | retail, wholesale, ecommerce, hospitality or construction. | |
| city | text | no | Delivery city (Saudi Arabia or GCC). | |
| customer_since | date | no | Contract start date. |
carriers
8 rows · primary key (carrier_id)Transport companies (including the in-house Sahra Fleet).
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| carrier_id | integer | no | PK | Unique carrier number. |
| carrier_name | text | no | unique | Name (fictional). |
| mode | text | no | road, air or sea. | |
| rating | numeric(5,2) | no | Procurement team's rating (1–5) at contract renewal; not computed from the data. |
routes
67 rows · primary key (route_id)Lanes: origin city, destination city and transport mode, with the standard transit time.
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| route_id | integer | no | PK | Unique route number. |
| origin_city | text | no | Origin (a warehouse city). | |
| destination_city | text | no | Destination city. | |
| mode | text | no | road, air or sea. | |
| distance_km | integer | no | Distance in km (25 for same-city deliveries). | |
| standard_days | integer | no | Standard transit days used to set promised_date. |
shipments
12,000 rows · primary key (shipment_id)Customer shipments (one consignment from a warehouse to a customer). Shipment-level only: no product lines.
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| shipment_id | integer | no | PK | Unique shipment number (ascending with creation time). |
| warehouse_id | integer | no | warehouses.warehouse_id | Dispatching warehouse. |
| customer_id | integer | no | customers.customer_id | Receiving customer. |
| carrier_id | integer | no | carriers.carrier_id | Carrier that moves the shipment. |
| route_id | integer | no | routes.route_id | Lane used (origin, destination, mode). |
| created_at | timestamp | no | When the shipment order was created in the warehouse system. | |
| shipped_at | timestamp | yes | When it left the warehouse. NULL = not dispatched yet (status created). | |
| promised_date | date | no | Delivery date promised to the customer. | |
| delivered_at | timestamp | yes | Proof-of-delivery time. NULL unless status = 'delivered'. | |
| status | text | no | Status on 2025-12-31: created, in_transit, delayed (in transit and past promised_date), delivered (on time or late), lost or returned. | |
| packages | integer | no | Number of packages / pallets. | |
| weight_kg | numeric(12,2) | yes | Chargeable weight in kg. NULL until weighed at dispatch. | |
| freight_cost | numeric(12,2) | no | Carrier charge in SAR (0 for goodwill re-deliveries). |
shipment_events
63,323 rows · primary key (event_id)Tracking scans for each shipment, in time order: picked, packed, dispatched, arrived_hub, out_for_delivery, delivered, plus exception and returned events.
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| event_id | integer | no | PK | Unique event number (ascending with time). |
| shipment_id | integer | no | shipments.shipment_id | The shipment scanned. |
| event_time | timestamp | no | When the scan happened. | |
| event_type | text | no | picked, packed, dispatched, arrived_hub, out_for_delivery, delivered, exception or returned. | |
| location | text | no | City where the scan happened. | |
| details | text | yes | Free text for exceptions and returns (e.g. 'Weather delay'). NULL for routine scans. |
purchase_orders
1,674 rows · primary key (po_id)Purchase orders to suppliers, one per supplier and receiving warehouse.
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| po_id | integer | no | PK | Unique purchase order number. |
| po_number | text | no | unique | Document number (PO-YY-#####). |
| supplier_id | integer | no | suppliers.supplier_id | Supplier. |
| warehouse_id | integer | no | warehouses.warehouse_id | Receiving warehouse. |
| ordered_on | date | no | Order date. | |
| expected_on | date | no | Expected delivery date (ordered_on + supplier lead time). | |
| received_on | date | yes | Date the goods were received. NULL for open or cancelled orders. | |
| status | text | no | open, received, partially_received (closed short) or cancelled. |
purchase_order_lines
2,995 rows · primary key (po_line_id)Products ordered on each purchase order.
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| po_line_id | integer | no | PK | Unique line number. |
| po_id | integer | no | purchase_orders.po_id | The purchase order. |
| product_id | integer | no | products.product_id | Product ordered. |
| quantity_ordered | integer | no | Units ordered. | |
| quantity_received | integer | no | Units received (0 for open or cancelled orders; less than ordered for partial deliveries). | |
| unit_cost | numeric(12,2) | no | Price paid per unit in SAR on this order. |
inventory_movements
7,702 rows · primary key (movement_id)Stock ledger: every change to on-hand quantity. on_hand at a date = sum(quantity) of all movements up to that date for the warehouse and product.
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| movement_id | integer | no | PK | Unique movement number (ascending with date). |
| warehouse_id | integer | no | warehouses.warehouse_id | Warehouse whose stock changed. |
| product_id | integer | no | products.product_id | Product whose stock changed. |
| movement_date | date | no | Posting date. | |
| movement_type | text | no | opening (balance on 2023-12-31), receipt (from a purchase order), outbound (monthly total shipped to customers, posted at month end) or adjustment. | |
| quantity | integer | no | Signed units: positive adds stock, negative removes it. | |
| po_line_id | integer | yes | purchase_order_lines.po_line_id | For receipts: the purchase order line received. NULL otherwise. |
| adjustment_reason | text | yes | For adjustments: shrinkage, damaged, expired or cycle_count (can be + or −). NULL otherwise. |
inventory_snapshots
4,421 rows · primary key (snapshot_date, warehouse_id, product_id)Month-end stock position per warehouse and product (only products the warehouse stocks).
| Column | Type | Null? | Key | Description |
|---|---|---|---|---|
| snapshot_date | date | no | PK | Last day of the month. |
| warehouse_id | integer | no | PK warehouses.warehouse_id | Warehouse. |
| product_id | integer | no | PK products.product_id | Product. |
| on_hand | integer | no | Units physically recorded in stock at the end of the day (can be negative after posting errors). | |
| allocated | integer | no | Units reserved for open customer orders. Available = on_hand − allocated. |