SQL Monthly Demand History Query Generator for Forecasting
Every statistical forecast starts with a clean time series, and most ERPs store transactions, not time series. This generator produces SQL that totals demand by item and month, fills months with no sales with zero, and returns the counts used for demand classification.
Fill in
Generic name. Replace with your ERP table or reporting view.
Use requested date for demand, shipped date for sales history.
PostgreSQL: monthly history with zero-filled gaps
WITH months AS (
SELECT generate_series(DATE '2024-01-01', DATE '2026-10-01' - INTERVAL '1 month', INTERVAL '1 month')::date AS month_start
),
items AS (
SELECT DISTINCT item_code AS item
FROM sales_order_lines
WHERE item_code LIKE 'BRK-%'
),
monthly AS (
SELECT item_code AS item,
DATE_TRUNC('month', ship_date)::date AS month_start,
SUM(qty_shipped) AS qty
FROM sales_order_lines
WHERE ship_date >= DATE '2024-01-01'
AND ship_date < DATE '2026-10-01'
AND item_code LIKE 'BRK-%'
GROUP BY item_code, DATE_TRUNC('month', ship_date)
)
SELECT i.item, m.month_start, COALESCE(d.qty, 0) AS qty
FROM items i
CROSS JOIN months m
LEFT JOIN monthly d ON d.item = i.item AND d.month_start = m.month_start
ORDER BY i.item, m.month_start;SQL Server: monthly totals
SELECT item_code AS item,
DATEFROMPARTS(YEAR(ship_date), MONTH(ship_date), 1) AS month_start,
SUM(qty_shipped) AS qty
FROM sales_order_lines
WHERE ship_date >= '2024-01-01'
AND ship_date < '2026-10-01'
AND item_code LIKE 'BRK-%'
GROUP BY item_code, DATEFROMPARTS(YEAR(ship_date), MONTH(ship_date), 1)
ORDER BY item_code, month_start;ADI inputs per item (PostgreSQL, run on the monthly result)
-- Wrap the first query as monthly_full(item, month_start, qty)
SELECT item,
COUNT(*) AS total_periods,
COUNT(*) FILTER (WHERE qty > 0) AS nonzero_periods,
AVG(qty) FILTER (WHERE qty > 0) AS mean_size,
STDDEV_SAMP(qty) FILTER (WHERE qty > 0) AS sd_size
FROM monthly_full
GROUP BY item;Table and column names are generic placeholders, not any specific ERP schema. Map them to your own table or view and remove cancelled, returned and intercompany lines before using the result as demand. Verify the date functions against your database version.
Demand history without hand-written SQL
Want to ask for item history in plain English? Ask for an optional expert review.
Optional. The tool and every export work without this. No spam.
How to use the generator
Fill in the table and column names from your ERP or reporting view, set the history window and an item filter, then copy the PostgreSQL or SQL Server block that matches your database. Run it, export the result to CSV and load it into Excel, Python or your planning tool. The zero-filled version matters, because missing months silently shorten the series and inflate averages.
Which date and quantity to use
Shipped quantity by ship date shows what customers actually received, but understates demand when you were out of stock. Order quantity by requested date is closer to true demand. Many planners use order lines by requested date for the statistical baseline and keep shipments for service level reporting. Choose one, document it and keep it constant.
- Remove returns and cancelled lines
- Exclude intercompany transfers
- Decide how to treat one-off project orders
- Keep the unit of measure consistent
Reading the output
You get one row per item per month, including zeros. A part with 36 rows and only 9 non-zero quantities is intermittent, which the third query quantifies with period counts, mean size and standard deviation. Feed those into the ADI and CV2 calculator to pick between smoothing and Croston style methods.
Common mistakes
Grouping by a timestamp column without truncating to the month gives thousands of rows. Using an inner join instead of the cross join drops zero months. Mixing units of measure across lines adds boxes to pieces. Always check that the total over the query equals a trusted sales report for one item before you load everything.
Frequently Asked Questions
Why fill missing months with zero?
A month with no sales is a valid observation of zero demand. If you omit it, the series is shorter, the average is too high and seasonal or intermittent patterns are distorted. Zero-fill before any statistical modelling.
Should demand history use orders or shipments?
Orders by requested date approximate demand better, because shipments are capped by supply. Shipments are easier to get and reconcile to finance. If you use shipments, flag periods with stock-outs and consider adjusting them.
Does this query work on SAP or Oracle tables?
The names are generic. The logic of grouping by item and month applies to any ERP, but you must map to the real tables or views, and review date functions and any client or organization filters for your system.
How do I get weekly history instead?
Replace the month truncation with a week truncation, for example DATE_TRUNC with the week unit in PostgreSQL, and change the generated series interval to one week. Keep the week start convention consistent.
If you would rather ask for this history in plain language and see the query it runs against your ERP, Netray can do that on-prem with read-only access.
Related Tools
Demand Pattern ADI and CV2 Classification Calculator
Enter a few counts from an item's demand history and get its ADI, CV2 and demand class so you can choose a suitable forecast method.
Developer ToolsPython Holt-Winters Forecast Script Generator
Generate a short Python script that fits Holt-Winters to monthly demand, tests it on a holdout against a naive baseline and writes the forecast to CSV.
Supply Chain & InventoryExcel Forecast Formula Generator (WMAPE, Bias, Tracking Signal)
Enter your actual and forecast ranges and get paste-ready Excel formulas for WMAPE, bias, MAE, RMSE and tracking signal.
Supply Chain & InventoryDemand Planning Data Readiness Checklist
Work through the data checks that decide whether a statistical forecast can be trusted, from history length to unit of measure and product hierarchy.
More Developer Tools tools
See all- SAP Sales Order ABAP SELECT Generator (VBAK, VBAP, VBFA)
- SAP Sales Order Create BAPI ABAP Generator (BAPI_SALESORDER_CREATEFROMDAT2)
- SAP ABAP Open Items SELECT Generator
- SAP ACDOCA SQL Query Generator
- SAP QM Inspection Lot ABAP SELECT Generator
- SAP Quality Notification Pareto SQL Query Generator
- SAP QM Usage Decision BAPI Skeleton
- ABAP Custom Exception Class Generator
- ABAP Unit Test Class Generator