SQL Running Total and Window Function Query Generator for ERP Tables
Running balances, change from the previous transaction and latest-N-per-item are everyday ERP report needs. This generator writes the window function version so you stop using slow self-joins.
Fill in
Running total per group
SELECT
item_code,
transaction_date,
transaction_id,
quantity_signed,
SUM(quantity_signed) OVER (
PARTITION BY item_code
ORDER BY transaction_date, transaction_id
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS running_total
FROM dbo.inventory_transactions
WHERE warehouse = 'MAIN'
ORDER BY item_code, transaction_date, transaction_id;Change from previous row
SELECT
item_code,
transaction_date,
quantity_signed,
LAG(quantity_signed) OVER (
PARTITION BY item_code
ORDER BY transaction_date, transaction_id
) AS previous_value,
quantity_signed - LAG(quantity_signed, 1, 0) OVER (
PARTITION BY item_code
ORDER BY transaction_date, transaction_id
) AS change_from_previous
FROM dbo.inventory_transactions
WHERE warehouse = 'MAIN';Latest N rows per group
WITH ranked AS (
SELECT
t.*,
ROW_NUMBER() OVER (
PARTITION BY item_code
ORDER BY transaction_date DESC, transaction_id DESC
) AS rn
FROM dbo.inventory_transactions AS t
WHERE warehouse = 'MAIN'
)
SELECT *
FROM ranked
WHERE rn <= 3
ORDER BY item_code, rn;Share of group total
SELECT
item_code,
transaction_date,
quantity_signed,
SUM(quantity_signed) OVER (PARTITION BY item_code) AS group_total,
CASE WHEN SUM(quantity_signed) OVER (PARTITION BY item_code) = 0
THEN 0
ELSE 100.0 * quantity_signed / SUM(quantity_signed) OVER (PARTITION BY item_code)
END AS pct_of_group
FROM dbo.inventory_transactions
WHERE warehouse = 'MAIN';Written in ANSI-style SQL that runs on SQL Server 2012 and later, Oracle, PostgreSQL and recent MySQL. Table and column names are placeholders for your ERP, so check them in your data dictionary. Test on a small date range first.
Optional report build
Tell us the balance report you need from your ERP and we will outline how to build it.
Optional. The tool and every export work without this. No spam.
How to use the generator
Enter the table or view name, the column that groups rows (item, account, customer), the column that orders them and a unique tie-breaker such as a transaction id. Set the amount column that should accumulate and an optional filter. Copy the query you need into your SQL tool. Replace the placeholders with real names from your ERP, and run first with a narrow filter so you can check the first few rows against the ERP screen.
Why the frame clause and tie-break matter
When ORDER BY is given without a frame, many engines default to RANGE, which treats rows with the same order value as one group. Two transactions posted at the same date would then show the same running total. Writing ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW and adding a unique tie-break column makes the result deterministic, and ROWS is also generally faster. Without a tie-break, results can change between runs.
Reading the output
For an inventory ledger the running total gives the balance after each movement, provided the quantity is signed (receipts positive, issues negative) and the query starts at the first transaction. If you filter by date, the running total starts at zero in the window, so add an opening balance. The latest-N query is useful for the last three receipt costs of an item, and the share of group total shows concentration, such as one customer holding most of the open balance.
Common mistakes
People often filter on a window result in the WHERE clause, which is not allowed because windows run after filtering. Wrap the query in a common table expression, as the latest-N block does. Others forget that NULL amounts propagate in LAG and SUM, apply the filter after the window so balances are wrong, or run it on unindexed tables with millions of rows. An index on the group and order columns helps greatly.
Frequently Asked Questions
Does this work on older SQL Server versions?
Running totals with an ordered window frame need SQL Server 2012 or later. On SQL Server 2008 you would use a correlated subquery or a cursor, which is much slower on large ledgers.
Why is my running total wrong on same-day rows?
Without a unique tie-break in the ORDER BY, rows with equal order values are arbitrary, and a default RANGE frame groups them. Add a unique column and use the ROWS frame as in the generated query.
Can I filter on the running total?
Not directly in the same SELECT. Wrap the query in a CTE or subquery and filter the outer query, for example to find the first date the balance went negative.
How do I start the balance from an opening figure?
Calculate the balance before your start date separately and add it to the running total, or run the window over the full history and filter the outer query by date.
If you want these report queries built against your actual ERP schema and scheduled to a share, we can build them with you.
Related Tools
SQL Monthly Pivot Query Generator (Conditional Aggregation)
Build a month-by-month cross-tab of any ERP amount, such as usage by item or sales by customer, using portable CASE and SUM logic.
Developer ToolsInventory Aging Buckets SQL Generator
Build an inventory aging query with your own table and column names and bucket sizes, ready to paste into SQL Server style SQL.
Developer ToolsERP Reporting Query Quality Assessment
Answer 10 questions about how your team writes, tests, documents and runs SQL reports on ERP data, and get a score with recommendations.
Developer ToolsERP SQL Query Catalog Worksheet
An editable inventory of the queries and reports your team runs, with owner, frequency, runtime and monthly effort.
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
Keep exploring
Free tools
- OEE SQL Query GeneratorFill in your table and column names and get a SQL query that calculates availability, performance, quality and OEE per line per day.
- PPAP Status Tracker SQL Query GeneratorFill in your table and column names and get SQL queries for overdue, pending and rejected PPAP submissions by supplier.
- Inspection Results SQL Query GeneratorFill in your own inspection table and column names to generate SQL for lot reject rate by supplier and top failing characteristics.
ERP fixes and how-tos
- Epicor Function Examples: Update a Table, Call It, Schedule ItWorked Epicor Kinetic Function examples: updating a table, calling a function from a BPM, Application Studio or REST, and scheduling a recurring run.
- How to create and call an Epicor FunctionHow to create Epicor Functions in Function Studio: define inputs and outputs, write the C# widget, test, then call the function from a BPM directive.
- Epicor Function Custom Code: C# Signature, Parameters and Calling ItWrite custom C# code in Epicor Functions: signature, request and response parameters, libraries, calling from BPM and Application Studio, with working examples.
Guides
- Reusable Script Function Library for SyteLine DevelopmentReusable SyteLine script function library. Copy-paste patterns for property access, IDO calls, validation, formatting, and UI control in CloudSuite Industrial forms.
- SQL Query Optimization for SyteLine ReportingOptimize SQL queries against Infor SyteLine database tables. Index strategies for SL tables, query plan analysis, and performance tuning for SSRS reports.
- LLM Integration Patterns for Enterprise ERP SystemsIntegrate large language models with enterprise ERP systems using RAG, fine-tuning, function calling, and prompt engineering patterns for production deployment.