Inventory Reorder Analysis — Identifying Stock Below Reorder Point
Inventory Reorder Analysis — Identifying Stock Below Reorder Point
Reorder analysis answers: which SKUs are below their reorder threshold, what quantity needs to be ordered, and what is the total replenishment cost?
1. Items Below Reorder Point
SELECT
w.code AS warehouse,
w.city,
s.sku,
s.name,
s.category,
i.quantity AS current_stock,
i.reorder_point,
i.reorder_qty,
i.reorder_point - i.quantity AS shortage,
ROUND(s.unit_cost * i.reorder_qty, 2) AS replenishment_cost_usd
FROM lg_inventory i
JOIN lg_warehouses w ON w.id = i.warehouse_id
JOIN lg_skus s ON s.id = i.sku_id
WHERE i.quantity < i.reorder_point
ORDER BY shortage DESC;
What This Returns
warehouse | city | sku_code | name | current_stock | reorder_point | shortage
----------+---------------+----------+----------+---------------+---------------+---------
US-NY | New York | SKU-002 | Widget B | 1 | 51 | 50
US-LA | Los Angeles | SKU-011 | Board A | 0 | 68 | 68
...
2. Reorder Summary by Warehouse
SELECT
w.code,
w.city,
COUNT(*) FILTER (WHERE i.quantity < i.reorder_point) AS skus_below_reorder,
COUNT(*) FILTER (WHERE i.quantity = 0) AS out_of_stock,
SUM(CASE WHEN i.quantity < i.reorder_point
THEN ROUND(s.unit_cost * i.reorder_qty, 2) ELSE 0 END) AS total_replenishment_cost_usd
FROM lg_inventory i
JOIN lg_warehouses w ON w.id = i.warehouse_id
JOIN lg_skus s ON s.id = i.sku_id
GROUP BY w.code, w.city
ORDER BY skus_below_reorder DESC;
3. Days of Stock Remaining (Estimated)
Using recent purchase order velocity as a proxy for consumption rate:
WITH consumption AS (
SELECT
warehouse_id,
sku_id,
SUM(quantity)::NUMERIC /
NULLIF(COUNT(DISTINCT DATE_TRUNC('month', ordered_at)), 0) AS avg_monthly_demand
FROM lg_purchase_orders
WHERE received_at IS NOT NULL
GROUP BY warehouse_id, sku_id
)
SELECT
w.code,
s.sku,
s.name,
i.quantity AS current_stock,
ROUND(c.avg_monthly_demand, 0) AS avg_monthly_demand,
ROUND(i.quantity / NULLIF(c.avg_monthly_demand / 30, 0), 0) AS days_of_stock_remaining
FROM lg_inventory i
JOIN lg_warehouses w ON w.id = i.warehouse_id
JOIN lg_skus s ON s.id = i.sku_id
LEFT JOIN consumption c
ON c.warehouse_id = i.warehouse_id AND c.sku_id = i.sku_id
ORDER BY days_of_stock_remaining NULLS LAST;
4. Open Purchase Orders That Will Cover the Shortage
Match in-transit POs against below-reorder inventory:
SELECT
w.code AS warehouse,
s.sku,
s.name,
i.quantity AS current_stock,
i.reorder_point,
po.quantity AS inbound_quantity,
po.expected_at,
po.status AS po_status,
i.quantity + po.quantity AS projected_stock_after_receipt
FROM lg_inventory i
JOIN lg_warehouses w ON w.id = i.warehouse_id
JOIN lg_skus s ON s.id = i.sku_id
JOIN lg_purchase_orders po
ON po.warehouse_id = i.warehouse_id
AND po.sku_id = i.sku_id
AND po.status IN ('pending','in_transit')
WHERE i.quantity < i.reorder_point
ORDER BY w.code, s.sku;
Key Takeaway
WHERE quantity < reorder_point with a LEFT JOIN to open POs lets you produce an actionable reorder report in a single query. Adding days_of_stock_remaining using a velocity calculation converts a static snapshot into a forward-looking risk indicator — a SKU with 0 days remaining requires different urgency than one with 5 days.