SyteLine Inventory Aging Query Generator
This generator builds an inventory aging query for SyteLine 9.x and CSI 10.x: quantity on hand by item, warehouse and location from itemloc_mst, aged by the last receipt date in matltran_mst and grouped into day buckets you choose. A summary block and a lot-based option are included.
Fill in
Example value only. Confirm receipt codes in your data with the decode query in the material transaction generator.
1. Aged on-hand by item, warehouse and location
DECLARE @Site SiteType = N'MAIN';
DECLARE @Whse NVARCHAR(10) = N'MAIN';
DECLARE @Item NVARCHAR(60) = N'%';
DECLARE @B1 INT = 30, @B2 INT = 60, @B3 INT = 90, @B4 INT = 180, @B5 INT = 365;
DECLARE @IncludeZeroCost BIT = 1;
IF OBJECT_ID('tempdb..#aged') IS NOT NULL DROP TABLE #aged;
WITH last_rcpt AS (
SELECT m.item, m.whse, m.loc, MAX(m.trans_date) AS last_rcpt_date
FROM matltran_mst AS m
WHERE m.site_ref = @Site
AND m.trans_type IN ('R')
GROUP BY m.item, m.whse, m.loc
)
SELECT il.item, il.whse, il.loc, il.qty_on_hand,
lr.last_rcpt_date,
DATEDIFF(day, lr.last_rcpt_date, GETDATE()) AS age_days,
ISNULL(i.unit_cost, 0) AS unit_cost,
il.qty_on_hand * ISNULL(i.unit_cost, 0) AS ext_value,
CASE WHEN lr.last_rcpt_date IS NULL THEN 7
WHEN DATEDIFF(day, lr.last_rcpt_date, GETDATE()) <= @B1 THEN 1
WHEN DATEDIFF(day, lr.last_rcpt_date, GETDATE()) <= @B2 THEN 2
WHEN DATEDIFF(day, lr.last_rcpt_date, GETDATE()) <= @B3 THEN 3
WHEN DATEDIFF(day, lr.last_rcpt_date, GETDATE()) <= @B4 THEN 4
WHEN DATEDIFF(day, lr.last_rcpt_date, GETDATE()) <= @B5 THEN 5
ELSE 6 END AS bucket_no
INTO #aged
FROM itemloc_mst AS il
JOIN item_mst AS i
ON i.site_ref = il.site_ref AND i.item = il.item
LEFT JOIN last_rcpt AS lr
ON lr.item = il.item AND lr.whse = il.whse AND lr.loc = il.loc
WHERE il.site_ref = @Site
AND (@Whse = N'' OR il.whse = @Whse)
AND il.item LIKE @Item
AND il.qty_on_hand <> 0
AND (@IncludeZeroCost = 1 OR ISNULL(i.unit_cost, 0) <> 0);
SELECT a.*,
CASE a.bucket_no
WHEN 1 THEN CONCAT('0-', @B1)
WHEN 2 THEN CONCAT(@B1 + 1, '-', @B2)
WHEN 3 THEN CONCAT(@B2 + 1, '-', @B3)
WHEN 4 THEN CONCAT(@B3 + 1, '-', @B4)
WHEN 5 THEN CONCAT(@B4 + 1, '-', @B5)
WHEN 6 THEN CONCAT('Over ', @B5)
ELSE 'No receipt found' END AS age_bucket
FROM #aged AS a
ORDER BY a.bucket_no DESC, a.ext_value DESC;2. Summary by bucket (same session, after block 1)
SELECT a.bucket_no,
COUNT(*) AS location_rows,
SUM(a.qty_on_hand) AS qty_on_hand,
SUM(a.ext_value) AS ext_value,
CAST(100.0 * SUM(a.ext_value) / NULLIF((SELECT SUM(ext_value) FROM #aged), 0) AS DECIMAL(6,2)) AS pct_of_value
FROM #aged AS a
GROUP BY a.bucket_no
ORDER BY a.bucket_no;
-- bucket_no 7 = no receipt found in matltran for that item, warehouse and location.3. Option: lot-tracked items aged by lot creation date
DECLARE @Site SiteType = N'MAIN';
DECLARE @Whse NVARCHAR(10) = N'MAIN';
DECLARE @Item NVARCHAR(60) = N'%';
-- CreateDate is the record audit column, used here as a proxy for lot age.
-- If your lot_mst holds a receipt or manufacture date you trust, age by that column instead.
SELECT ll.item, ll.whse, ll.loc, ll.lot, ll.qty_on_hand,
l.CreateDate AS lot_created,
DATEDIFF(day, l.CreateDate, GETDATE()) AS age_days
FROM lot_loc_mst AS ll
JOIN lot_mst AS l
ON l.site_ref = ll.site_ref AND l.item = ll.item AND l.lot = ll.lot
WHERE ll.site_ref = @Site
AND (@Whse = N'' OR ll.whse = @Whse)
AND ll.item LIKE @Item
AND ll.qty_on_hand <> 0
ORDER BY age_days DESC;Confirm on your SyteLine 9/10 database: itemloc_mst.qty_on_hand, the item cost column you value at (unit_cost on item_mst by default), the lot_loc_mst and lot_mst columns, and the receipt trans_type codes. Values use item unit cost, not costed layers, so this is an operational aging view, not an accounting valuation. Run on a reporting copy where possible.
Aging report reconciliation
Send your bucket summary and the standard valuation total; we will help explain the difference and tune the receipt codes.
Optional. The tool and every export work without this. No spam.
How to use it
Set the site, warehouse and item filter, then the five bucket edges, for example 30, 60, 90, 180 and 365 days. Enter the receipt transaction codes you have confirmed in your data, and the item cost column to value at. Run block 1 in SSMS: it stores the aged rows in a temporary table and lists them oldest first. Run block 2 in the same window to get quantity, value and percent of value per bucket. Use block 3 for lot-tracked items when lot creation is a better age signal than the last receipt to a location.
- Bucket edges must increase from 1 to 5.
- Rows with no receipt found fall into bucket 7; investigate them separately.
- Exclude zero-cost items when the report is for finance.
The method and its limits
Age here is days since the most recent receipt into that item, warehouse and location. That is a proxy, not true FIFO layer age: if 100 units were received a year ago and 5 last week, the whole 105 shows as one week old. Moves between locations post new transactions, so stock that moved recently can look young unless you age by item and warehouse only (drop loc from the CTE and join). Value is quantity on hand times the item unit cost, which matches neither actual nor FIFO cost exactly. For a defensible accounting number, use the costing reports.
Worked example
A site has 2,400 location rows with stock. Block 2 shows 61 percent of value received in the last 90 days, 14 percent between 91 and 180, 9 percent between 181 and 365, 11 percent over a year and 5 percent with no receipt found. The over-a-year bucket lists PN-30117 with 800 units at 12.50, worth 10,000. The no-receipt bucket usually holds stock loaded at go-live, items received under codes missing from the receipt list, or lot moves; fix the code list before trusting the report.
Gotchas
Missing receipt codes make stock look older than it is, so check the code list first. Multi-site databases need the site_ref filter on every join, which the query applies through the item and location joins. Negative on-hand rows appear because the filter is non-zero; review them, they usually point to backflush or timing issues. If the item cost column you value at is zero for purchased items, the cost rollup may not have run; the zero-cost switch lets you see them or exclude them.
Frequently Asked Questions
Does SyteLine have a standard inventory aging report?
SyteLine includes inventory and valuation reports, but sites often need aging by location with their own buckets and an Excel-friendly output. A query like this gives that control. Compare its totals with the standard valuation report for the same date before you circulate it.
Why age by last receipt instead of FIFO layers?
Last receipt is simple, fast and available for every costing method. FIFO layer age requires the cost layer tables and costing method in use, which differ by setup. Last receipt understates age when small receipts top up old stock, so treat the result as an operational signal.
How do I export the aging report to Excel?
Run block 1 or 2 in SSMS and copy with headers, or save the results as CSV. For a refreshable workbook, put the logic in a view or procedure on a reporting copy and connect Excel to it through Get Data from SQL Server with a read-only login.
Why do some rows show no receipt found?
The location has stock but no matching receipt transaction: opening balances loaded at go-live, receipts under codes not in your list, stock moved in from another location, or history purged. Add missing codes, or age those rows by item and warehouse or by lot instead.
If finance and planning want to ask SyteLine which stock is ageing in plain English, we can set up a private, read-only assistant over these tables on your own servers.
Related Tools
SyteLine Material Transaction History Query Generator
Build SQL Server queries over SyteLine material transactions for detail history, monthly usage by item and decoding the transaction codes in your data.
Costing & FinanceSyteLine Excess and Obsolete Inventory Review Template
A review and approval form for documenting why an item is excess or obsolete and what you decided to do with it.
Costing & FinanceSyteLine Inventory Carrying Cost and Turns Calculator
Compute inventory turns, days on hand and the yearly cost of carrying stock, then see the cash and savings from a higher turn target.
Infor SyteLineSyteLine Database Tables Reference
Searchable lookup of the main SyteLine SQL tables, what each holds and its usual business key, for writing queries and reports.
More Developer Tools tools
See all- SyteLine IDO REST Request Generator
- SyteLine SQL Query Generator for Item, Job and Order Tables
- SyteLine SQL Blocking and Long Running Query Script Generator
- SyteLine Custom Table CREATE Script Generator
- SyteLine Mongoose Framework Events Reference
- SyteLine Event Action Types Reference
- SyteLine Event Action Parameter Functions Reference
- SyteLine WinStudio Standard Form Events Reference
- SyteLine Mongoose API Options Reference
Keep exploring
Free tools
- Inventory Aging Buckets SQL GeneratorBuild an inventory aging query with your own table and column names and bucket sizes, ready to paste into SQL Server style SQL.
- WMS Bin Inventory and Aging SQL GeneratorBuild starter SQL for stock by bin, aging buckets and mixed-item bins against your own inventory table, in three SQL dialects.
- SyteLine Open Purchase Order Query GeneratorBuilds a read-only SQL query for open and late PO lines in SyteLine 9/10, with a second query for vendor on-time delivery from PO receipts.