FIFOdet
Updated: 13 Jul 2023
Use the SQL Server table-valued function FIFOdet to calculate FIFO (First In, First Out) values in an ordered resultant table. FIFOdet calculates balances for each value from the first value to the last value in the ordered group or partition. FIFOdet returns:
- the transaction identifier,
- output row number,
- transaction quantity,
- transaction unit price,
- transaction extended price,
- inventory on hand including the current transaction,
- inventory cost including the current transaction,
- cost of goods sold,
- gross margin on sale,
- the transaction identifier of the purchase from which the sale transaction was filled,
- the quantity from the purchase transaction identifier, and
- the unit price from the purchase transaction identifier.
FIFOdet assumes that the quantity i.e., the number of units, of the transaction and the monetary value of the transaction have the same sign. Purchase, or additions to inventory, are positive and sales, or withdrawals from inventory, are negative.
FIFOdet will match the first sale transaction with the first purchase transaction. If the sale quantity is less than the purchased quantity, then the remaining balance on the purchase transaction will be applied to the next sale transaction. If the sale quantity is greater than the purchased quantity then FIFOdet will get the next purchase transaction, repeating this process until the remaining balance on the sales transaction is zero or there is no more inventory.
In the event that amount sold is greater than the amount purchased, then the inventory on hand will continue to be updated, but the inventory cost will be zero.
Syntax
SELECT * FROM [wct].[FIFOdet] (
<@DataQuery, nvarchar(max),>)
Arguments
Input Name | Description |
@DataQuery | An SQL statement which returns a resultant table containing the unique transaction identifier, quantity and amount. |
Return Type
RETURNS TABLE (
[ID] [sql_variant] NULL,
[RN] [int] NULL,
[QTY] [float] NULL,
[UNITPRICE] [float] NULL,
[EXPRICE] [float] NULL,
[INVONHAND] [float] NULL,
[INVCOST] [float] NULL,
[COGS] [float] NULL,
[GM] [float] NULL,
[PURID] [sql_variant] NULL,
[PURQTY] [float] NULL,
[PURPRICE] [float] NULL
)
Column | Description |
ID | unique transaction identifier |
RN | output row number |
QTY | transaction quantity |
UNITPRICE | transaction unit price |
EXPRICE | transaction extended price |
INVONHAND | the sum of QTY for the current and all preceding rows |
INVCOST | the inventory cost from the preceding row plus the costs of good sold from the current row |
COGS | the cost of goods sold for the current row |
GM | the gross margin on sales for the current row |
PURID | the transaction identifier of the purchase transaction used in the calculation of the cost of goods sold |
PURQTY | the quantity used from purchase transaction |
PURPRICE | The unit price from the purchase transaction |
Remarks
- For purchase transactions i.e., where QTY > 0, COGS, GM, PURID, PURQTY and PURPRICE will be NULL.
- If INVONHAND <= 0 then INVCOST = 0.
- The number of rows returned by the function may be greater than the number of input rows. The RN column in the resultant table should be used in your SQL to return the output rows in the order in which they were processed by the function.
Examples
Example #1
This is a very simple example showing the movements for one product over the month of June. Since it only involves one product, there is no product identifier in the SQL. The input had been put in date order and then in quantity descending order within date.
SET NOCOUNT ON;
DROP TABLE IF EXISTS #t;
SELECT
*
INTO
#t
FROM (VALUES
('20230615001','2023-06-15',-411,11.86)
,('20230625002','2023-06-25',-921,11.9)
,('20230628003','2023-06-28',-178,11.77)
,('20230622004','2023-06-22',742,10.75)
,('20230629005','2023-06-29',-537,11.91)
,('20230627006','2023-06-27',639,10.59)
,('20230606007','2023-06-06',199,10.71)
,('20230607008','2023-06-07',-215,11.9)
,('20230623009','2023-06-23',-540,11.95)
,('20230615010','2023-06-15',699,10.64)
,('20230630011','2023-06-30',478,10.64)
,('20230605012','2023-06-05',658,10.65)
,('20230612013','2023-06-12',-974,11.87)
,('20230603014','2023-06-03',-704,11.96)
,('20230603015','2023-06-03',-497,11.89)
,('20230606016','2023-06-06',231,10.52)
,('20230627017','2023-06-27',96,10.73)
,('20230604018','2023-06-04',860,10.51)
,('20230624019','2023-06-24',-323,11.94)
,('20230606020','2023-06-06',762,10.7)
,('20230624021','2023-06-24',-211,11.8)
,('20230628022','2023-06-28',-195,11.8)
,('20230617023','2023-06-17',480,10.75)
,('20230629024','2023-06-29',-950,12)
,('20230621025','2023-06-21',703,10.72)
,('20230629026','2023-06-29',551,10.7)
,('20230628027','2023-06-28',-631,11.81)
,('20230608028','2023-06-08',448,10.7)
,('20230613029','2023-06-13',-909,11.97)
,('20230621030','2023-06-21',762,10.56)
)n(ordno,orddate,qty,price)
SELECT
CAST(k.ID as CHAR(13)) as ID
,t.orddate as orddate
,ROUND(k.QTY, 4) as QTY
,ROUND(k.UNITPRICE, 4) as UNITPRICE
,ROUND(k.EXPRICE, 4) as EXPRICE
,ROUND(k.INVONHAND, 4) as INVONHAND
,ROUND(k.INVCOST, 4) as INVCOST
,ROUND(k.COGS, 4) as COGS
,ROUND(k.GM, 4) as GM
,CAST(k.PURID as CHAR(13)) as PURID
,ROUND(k.PURQTY, 4) as PURQTY
,ROUND(k.PURPRICE, 4) as PURPRICE
FROM
wct.FIFOdet('SELECT ordno, qty, qty * price FROM #t ORDER BY ORDDATE ASC, qty DESC')k
INNER JOIN
#t t
ON
k.ID = t.ordno
ORDER BY
k.RN
This produces the following result.
Note that there were 30 input rows and 44 output rows. You should also make note of the fact that the first purchase transaction occurs after the first sale transaction.
Example #2
In this example, we calculate the FIFO balances for multiple products. Doing so requires the use of a CROSS APPLY. In addition to the CROSS APPLY we JOIN to the source table to include the product identifier (and any other data that might be of interest) in the resultant table.
SET NOCOUNT ON;
DROP TABLE IF EXISTS #t;
SELECT
*
INTO
#t
FROM (VALUES
('5FCDA993-9C22-5B41-95DD-58993D627827','20230601001','2023-06-01',-791,11.81)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230619002','2023-06-19',-914,11.8)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230603003','2023-06-03',-728,11.8)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230612004','2023-06-12',-792,11.93)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230611005','2023-06-11',-926,11.85)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230614006','2023-06-14',295,10.75)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230619007','2023-06-19',-13,11.86)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230604008','2023-06-04',435,10.55)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230616009','2023-06-16',314,10.72)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230605010','2023-06-05',72,10.62)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230614011','2023-06-14',271,10.72)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230610012','2023-06-10',486,10.51)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230608013','2023-06-08',394,10.56)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230630014','2023-06-30',634,10.71)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230616015','2023-06-16',-201,11.92)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230622016','2023-06-22',646,10.75)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230601017','2023-06-01',139,10.62)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230626018','2023-06-26',-892,11.77)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230604019','2023-06-04',925,10.56)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230621020','2023-06-21',87,10.74)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230625021','2023-06-25',-560,12)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230601022','2023-06-01',-124,11.99)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230601023','2023-06-01',-760,11.86)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230619024','2023-06-19',664,10.56)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230602025','2023-06-02',-527,11.78)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230623026','2023-06-23',-749,11.79)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230617027','2023-06-17',724,10.72)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230629028','2023-06-29',-691,11.86)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230608029','2023-06-08',124,10.59)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230613030','2023-06-13',-970,11.86)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230615032','2023-06-15',-225,119.08)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230627033','2023-06-27',453,107.14)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230625034','2023-06-25',-475,118.07)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230613035','2023-06-13',-443,118.19)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230620036','2023-06-20',-480,118.63)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230618037','2023-06-18',-352,118.84)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230603038','2023-06-03',345,106.01)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230623039','2023-06-23',-126,118.62)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230610040','2023-06-10',317,107.23)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230603041','2023-06-03',265,105.35)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230615042','2023-06-15',-278,119.92)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230623043','2023-06-23',44,105.1)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230619044','2023-06-19',429,105.14)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230614045','2023-06-14',-419,119.83)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230606046','2023-06-06',100,107.35)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230615047','2023-06-15',358,105.51)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230601048','2023-06-01',351,106.45)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230624049','2023-06-24',-26,119.94)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230615050','2023-06-15',25,106.49)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230629051','2023-06-29',352,106.48)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230611052','2023-06-11',238,106.6)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230630053','2023-06-30',144,107.36)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230602054','2023-06-02',316,105.77)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230606055','2023-06-06',48,107.02)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230624056','2023-06-24',398,106.14)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230627057','2023-06-27',279,106.63)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230616058','2023-06-16',-427,117.55)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230624059','2023-06-24',375,106.75)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230630060','2023-06-30',17,105.13)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230601061','2023-06-01',-92,119.49)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230630063','2023-06-30',-122,10.53)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230604064','2023-06-04',153,11.86)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230629065','2023-06-29',183,12)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230620066','2023-06-20',-144,10.65)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230607067','2023-06-07',-36,10.51)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230603068','2023-06-03',70,11.93)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230616069','2023-06-16',-136,10.73)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230608070','2023-06-08',171,11.86)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230608071','2023-06-08',166,11.75)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230629072','2023-06-29',0,10.74)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230622073','2023-06-22',79,11.86)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230605074','2023-06-05',-115,10.52)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230617075','2023-06-17',-112,10.58)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230606076','2023-06-06',182,11.93)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230630077','2023-06-30',29,11.99)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230602078','2023-06-02',6,11.78)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230620079','2023-06-20',-51,10.51)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230619080','2023-06-19',-107,10.57)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230618081','2023-06-18',-110,10.66)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230629082','2023-06-29',198,11.84)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230607083','2023-06-07',-48,10.61)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230627084','2023-06-27',-118,10.56)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230612085','2023-06-12',35,11.87)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230622086','2023-06-22',76,11.93)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230617087','2023-06-17',-63,10.58)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230621088','2023-06-21',33,12)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230605089','2023-06-05',-23,10.71)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230617090','2023-06-17',19,11.9)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230622091','2023-06-22',121,11.84)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230629092','2023-06-29',172,11.96)
,('24202201-1770-0D9D-3543-CD78799A9415','20230624094','2023-06-24',-41,106.62)
,('24202201-1770-0D9D-3543-CD78799A9415','20230622095','2023-06-22',-19,107.12)
,('24202201-1770-0D9D-3543-CD78799A9415','20230619096','2023-06-19',23,119.33)
,('24202201-1770-0D9D-3543-CD78799A9415','20230630097','2023-06-30',62,119.9)
,('24202201-1770-0D9D-3543-CD78799A9415','20230618098','2023-06-18',52,119.01)
,('24202201-1770-0D9D-3543-CD78799A9415','20230618099','2023-06-18',-70,105.3)
,('24202201-1770-0D9D-3543-CD78799A9415','20230607100','2023-06-07',47,118.46)
,('24202201-1770-0D9D-3543-CD78799A9415','20230613101','2023-06-13',-13,105.71)
,('24202201-1770-0D9D-3543-CD78799A9415','20230622102','2023-06-22',-99,105.99)
,('24202201-1770-0D9D-3543-CD78799A9415','20230608103','2023-06-08',8,118.3)
,('24202201-1770-0D9D-3543-CD78799A9415','20230619104','2023-06-19',22,118.98)
,('24202201-1770-0D9D-3543-CD78799A9415','20230629105','2023-06-29',88,118.06)
,('24202201-1770-0D9D-3543-CD78799A9415','20230616106','2023-06-16',-8,106.11)
,('24202201-1770-0D9D-3543-CD78799A9415','20230612107','2023-06-12',92,117.63)
,('24202201-1770-0D9D-3543-CD78799A9415','20230607108','2023-06-07',-37,106.05)
,('24202201-1770-0D9D-3543-CD78799A9415','20230603109','2023-06-03',85,118.03)
,('24202201-1770-0D9D-3543-CD78799A9415','20230605110','2023-06-05',41,119.04)
,('24202201-1770-0D9D-3543-CD78799A9415','20230628111','2023-06-28',-22,107.41)
,('24202201-1770-0D9D-3543-CD78799A9415','20230617112','2023-06-17',-91,105.54)
,('24202201-1770-0D9D-3543-CD78799A9415','20230605113','2023-06-05',-20,106.43)
,('24202201-1770-0D9D-3543-CD78799A9415','20230612114','2023-06-12',-39,107.2)
,('24202201-1770-0D9D-3543-CD78799A9415','20230629115','2023-06-29',37,117.58)
,('24202201-1770-0D9D-3543-CD78799A9415','20230605116','2023-06-05',15,117.66)
,('24202201-1770-0D9D-3543-CD78799A9415','20230630117','2023-06-30',43,117.65)
,('24202201-1770-0D9D-3543-CD78799A9415','20230611118','2023-06-11',-33,106.14)
,('24202201-1770-0D9D-3543-CD78799A9415','20230624119','2023-06-24',-47,105.1)
,('24202201-1770-0D9D-3543-CD78799A9415','20230614120','2023-06-14',-17,105.41)
,('24202201-1770-0D9D-3543-CD78799A9415','20230602121','2023-06-02',-93,107.36)
,('24202201-1770-0D9D-3543-CD78799A9415','20230621122','2023-06-21',-90,105.91)
,('24202201-1770-0D9D-3543-CD78799A9415','20230612123','2023-06-12',18,119.58)
)n(id_item,ordno,orddate,qty,price)
SELECT
a.id_item
,CAST(k.ID as CHAR(36)) as ID
,t.orddate as orddate
,ROUND(k.QTY, 4) as QTY
,ROUND(k.UNITPRICE, 4) as UNITPRICE
,ROUND(k.EXPRICE, 4) as EXPRICE
,ROUND(k.INVONHAND, 4) as INVONHAND
,ROUND(k.INVCOST, 4) as INVCOST
,ROUND(k.COGS, 4) as COGS
,ROUND(k.GM, 4) as GM
,CAST(k.PURID as CHAR(36)) as PURID
,ROUND(k.PURQTY, 4) as PURQTY
,ROUND(k.PURPRICE, 4) as PURPRICE
FROM
(SELECT DISTINCT id_item FROM #t)a
CROSS APPLY
wct.FIFOdet('SELECT ordno, qty, qty * price FROM #t WHERE id_item = ''' + a.id_item + ''' ORDER BY ORDDATE ASC, qty DESC')k
INNER JOIN
#t t
ON
k.ID = t.ordno
ORDER BY
a.id_item
,k.RN
This produces the following result.
Example #3
In this example, there is a separate table (#i) for all the inventory items and a table for the transactions (#t). This SQL will calculate the FIFO values without having to get the distinct product identifiers from the transaction table.
SET NOCOUNT ON;
DROP TABLE IF EXISTS #t;
DROP TABLE IF EXISTS #i;
SELECT
*
INTO
#i
FROM (VALUES
('24202201-1770-0D9D-3543-CD78799A9415')
,('5FCDA993-9C22-5B41-95DD-58993D627827')
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55')
,('E412D80E-6993-43D8-38BB-E61EAFD158FF')
,('C85837C2-69EF-5A55-0BF3-8D48269B237D')
,('388E9D84-6256-0E51-8DA1-0923AA739232')
,('4C54AC48-2109-3E57-2D65-EA43A2B64FFE')
,('BF97105A-35FA-7E42-6F30-A3C908A12203')
)n(id)
SELECT
*
INTO
#t
FROM (VALUES
('5FCDA993-9C22-5B41-95DD-58993D627827','20230601001','2023-06-01',-791,11.81)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230619002','2023-06-19',-914,11.8)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230603003','2023-06-03',-728,11.8)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230612004','2023-06-12',-792,11.93)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230611005','2023-06-11',-926,11.85)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230614006','2023-06-14',295,10.75)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230619007','2023-06-19',-13,11.86)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230604008','2023-06-04',435,10.55)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230616009','2023-06-16',314,10.72)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230605010','2023-06-05',72,10.62)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230614011','2023-06-14',271,10.72)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230610012','2023-06-10',486,10.51)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230608013','2023-06-08',394,10.56)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230630014','2023-06-30',634,10.71)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230616015','2023-06-16',-201,11.92)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230622016','2023-06-22',646,10.75)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230601017','2023-06-01',139,10.62)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230626018','2023-06-26',-892,11.77)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230604019','2023-06-04',925,10.56)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230621020','2023-06-21',87,10.74)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230625021','2023-06-25',-560,12)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230601022','2023-06-01',-124,11.99)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230601023','2023-06-01',-760,11.86)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230619024','2023-06-19',664,10.56)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230602025','2023-06-02',-527,11.78)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230623026','2023-06-23',-749,11.79)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230617027','2023-06-17',724,10.72)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230629028','2023-06-29',-691,11.86)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230608029','2023-06-08',124,10.59)
,('5FCDA993-9C22-5B41-95DD-58993D627827','20230613030','2023-06-13',-970,11.86)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230615032','2023-06-15',-225,119.08)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230627033','2023-06-27',453,107.14)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230625034','2023-06-25',-475,118.07)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230613035','2023-06-13',-443,118.19)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230620036','2023-06-20',-480,118.63)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230618037','2023-06-18',-352,118.84)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230603038','2023-06-03',345,106.01)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230623039','2023-06-23',-126,118.62)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230610040','2023-06-10',317,107.23)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230603041','2023-06-03',265,105.35)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230615042','2023-06-15',-278,119.92)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230623043','2023-06-23',44,105.1)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230619044','2023-06-19',429,105.14)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230614045','2023-06-14',-419,119.83)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230606046','2023-06-06',100,107.35)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230615047','2023-06-15',358,105.51)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230601048','2023-06-01',351,106.45)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230624049','2023-06-24',-26,119.94)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230615050','2023-06-15',25,106.49)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230629051','2023-06-29',352,106.48)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230611052','2023-06-11',238,106.6)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230630053','2023-06-30',144,107.36)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230602054','2023-06-02',316,105.77)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230606055','2023-06-06',48,107.02)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230624056','2023-06-24',398,106.14)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230627057','2023-06-27',279,106.63)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230616058','2023-06-16',-427,117.55)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230624059','2023-06-24',375,106.75)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230630060','2023-06-30',17,105.13)
,('E412D80E-6993-43D8-38BB-E61EAFD158FF','20230601061','2023-06-01',-92,119.49)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230630063','2023-06-30',-122,10.53)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230604064','2023-06-04',153,11.86)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230629065','2023-06-29',183,12)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230620066','2023-06-20',-144,10.65)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230607067','2023-06-07',-36,10.51)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230603068','2023-06-03',70,11.93)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230616069','2023-06-16',-136,10.73)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230608070','2023-06-08',171,11.86)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230608071','2023-06-08',166,11.75)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230629072','2023-06-29',0,10.74)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230622073','2023-06-22',79,11.86)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230605074','2023-06-05',-115,10.52)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230617075','2023-06-17',-112,10.58)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230606076','2023-06-06',182,11.93)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230630077','2023-06-30',29,11.99)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230602078','2023-06-02',6,11.78)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230620079','2023-06-20',-51,10.51)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230619080','2023-06-19',-107,10.57)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230618081','2023-06-18',-110,10.66)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230629082','2023-06-29',198,11.84)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230607083','2023-06-07',-48,10.61)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230627084','2023-06-27',-118,10.56)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230612085','2023-06-12',35,11.87)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230622086','2023-06-22',76,11.93)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230617087','2023-06-17',-63,10.58)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230621088','2023-06-21',33,12)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230605089','2023-06-05',-23,10.71)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230617090','2023-06-17',19,11.9)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230622091','2023-06-22',121,11.84)
,('E3FDD639-540F-0CE1-4C04-ED48E7F44D55','20230629092','2023-06-29',172,11.96)
,('24202201-1770-0D9D-3543-CD78799A9415','20230624094','2023-06-24',-41,106.62)
,('24202201-1770-0D9D-3543-CD78799A9415','20230622095','2023-06-22',-19,107.12)
,('24202201-1770-0D9D-3543-CD78799A9415','20230619096','2023-06-19',23,119.33)
,('24202201-1770-0D9D-3543-CD78799A9415','20230630097','2023-06-30',62,119.9)
,('24202201-1770-0D9D-3543-CD78799A9415','20230618098','2023-06-18',52,119.01)
,('24202201-1770-0D9D-3543-CD78799A9415','20230618099','2023-06-18',-70,105.3)
,('24202201-1770-0D9D-3543-CD78799A9415','20230607100','2023-06-07',47,118.46)
,('24202201-1770-0D9D-3543-CD78799A9415','20230613101','2023-06-13',-13,105.71)
,('24202201-1770-0D9D-3543-CD78799A9415','20230622102','2023-06-22',-99,105.99)
,('24202201-1770-0D9D-3543-CD78799A9415','20230608103','2023-06-08',8,118.3)
,('24202201-1770-0D9D-3543-CD78799A9415','20230619104','2023-06-19',22,118.98)
,('24202201-1770-0D9D-3543-CD78799A9415','20230629105','2023-06-29',88,118.06)
,('24202201-1770-0D9D-3543-CD78799A9415','20230616106','2023-06-16',-8,106.11)
,('24202201-1770-0D9D-3543-CD78799A9415','20230612107','2023-06-12',92,117.63)
,('24202201-1770-0D9D-3543-CD78799A9415','20230607108','2023-06-07',-37,106.05)
,('24202201-1770-0D9D-3543-CD78799A9415','20230603109','2023-06-03',85,118.03)
,('24202201-1770-0D9D-3543-CD78799A9415','20230605110','2023-06-05',41,119.04)
,('24202201-1770-0D9D-3543-CD78799A9415','20230628111','2023-06-28',-22,107.41)
,('24202201-1770-0D9D-3543-CD78799A9415','20230617112','2023-06-17',-91,105.54)
,('24202201-1770-0D9D-3543-CD78799A9415','20230605113','2023-06-05',-20,106.43)
,('24202201-1770-0D9D-3543-CD78799A9415','20230612114','2023-06-12',-39,107.2)
,('24202201-1770-0D9D-3543-CD78799A9415','20230629115','2023-06-29',37,117.58)
,('24202201-1770-0D9D-3543-CD78799A9415','20230605116','2023-06-05',15,117.66)
,('24202201-1770-0D9D-3543-CD78799A9415','20230630117','2023-06-30',43,117.65)
,('24202201-1770-0D9D-3543-CD78799A9415','20230611118','2023-06-11',-33,106.14)
,('24202201-1770-0D9D-3543-CD78799A9415','20230624119','2023-06-24',-47,105.1)
,('24202201-1770-0D9D-3543-CD78799A9415','20230614120','2023-06-14',-17,105.41)
,('24202201-1770-0D9D-3543-CD78799A9415','20230602121','2023-06-02',-93,107.36)
,('24202201-1770-0D9D-3543-CD78799A9415','20230621122','2023-06-21',-90,105.91)
,('24202201-1770-0D9D-3543-CD78799A9415','20230612123','2023-06-12',18,119.58)
)n(id_item,ordno,orddate,qty,price)
SELECT
a.id_item
,CAST(k.ID as CHAR(11)) as ID
,t.orddate as orddate
,ROUND(k.QTY, 4) as QTY
,ROUND(k.UNITPRICE, 4) as UNITPRICE
,ROUND(k.EXPRICE, 4) as EXPRICE
,ROUND(k.INVONHAND, 4) as INVONHAND
,ROUND(k.INVCOST, 4) as INVCOST
,ROUND(k.COGS, 4) as COGS
,ROUND(k.GM, 4) as GM
,CAST(k.PURID as CHAR(36)) as PURID
,ROUND(k.PURQTY, 4) as PURQTY
,ROUND(k.PURPRICE, 4) as PURPRICE
FROM
(SELECT id as id_item FROM #i)a
CROSS APPLY
wct.FIFOdet('SELECT ordno, qty, qty * price FROM #t WHERE id_item = ''' + a.id_item + ''' ORDER BY ORDDATE ASC, qty DESC')k
INNER JOIN
#t t
ON
k.ID = t.ordno
ORDER BY
a.id_item
,k.RN
This produces the following result.
Example #4
In this example we show how to get the ending inventories balances. We put some transaction date in #t and then use FIFOdet to put the inventory calculations in #fifo. We then execute SQL to get the ending inventory on hand and the cost of that inventory for each product in #fifo.
SET NOCOUNT ON;
DROP TABLE IF EXISTS #t;
DROP TABLE IF EXISTS #fifo;
SELECT
*
INTO
#t
FROM
(VALUES
('2020-11-18-002','PROD-000174','2020-11-18',223.18,921.06,205562.1708)
,('2022-04-15-009','PROD-000536','2022-04-15',187.13,73.54,13761.5402)
,('2022-04-17-002','PROD-000790','2022-04-17',50.43,307.51,15507.7293)
,('2020-09-03-007','PROD-000174','2020-09-03',235.1,570.99,134239.749)
,('2020-09-03-008','PROD-000536','2020-09-03',4.47,101.87,455.3589)
,('2021-05-19-001','PROD-000536','2021-05-19',-22.05,603.67,-13310.9235)
,('2021-12-05-008','PROD-001503','2021-12-05',-12.8,1449.14,-18548.992)
,('2022-03-30-003','PROD-000790','2022-03-30',-457.17,327.93,-149919.7581)
,('2022-07-18-008','PROD-000790','2022-07-18',-440.99,239.53,-105630.3347)
,('2022-07-18-010','PROD-000536','2022-07-18',-21.18,466.12,-9872.4216)
,('2020-12-29-008','PROD-000174','2020-12-29',-258.02,896.95,-231431.039)
,('2021-12-18-006','PROD-001503','2021-12-18',-62.66,119.22,-7470.3252)
,('2022-02-11-001','PROD-000174','2022-02-11',183.58,861.8,158209.244)
,('2022-02-12-004','PROD-000174','2022-02-12',251.96,751.35,189310.146)
,('2022-05-05-004','PROD-001503','2022-05-05',-44.83,464,-20801.12)
,('2023-05-23-001','PROD-000790','2023-05-23',-305.53,386.39,-118053.7367)
,('2020-07-17-003','PROD-000174','2020-07-17',-94.4,529.46,-49981.024)
,('2021-11-16-009','PROD-001503','2021-11-16',-34.56,1664.7,-57532.032)
,('2021-11-17-005','PROD-001503','2021-11-17',-49.98,1406.02,-70272.8796)
,('2021-11-19-007','PROD-001503','2021-11-19',-66.05,64.29,-4246.3545)
,('2022-03-08-007','PROD-000536','2022-03-08',28.94,69.75,2018.565)
,('2022-03-15-002','PROD-000536','2022-03-15',-1.98,570.72,-1130.0256)
,('2022-06-08-002','PROD-001503','2022-06-08',-20.28,305.35,-6192.498)
,('2022-06-13-003','PROD-000536','2022-06-13',128.65,46.35,5962.9275)
,('2021-08-08-004','PROD-000536','2021-08-08',152.55,85.52,13046.076)
,('2022-05-27-001','PROD-001503','2022-05-27',-11.62,1877.09,-21811.7858)
,('2022-08-25-006','PROD-000790','2022-08-25',-179.22,233.08,-41772.5976)
,('2021-05-20-005','PROD-000174','2021-05-20',507.47,808.33,410203.2251)
,('2021-11-03-003','PROD-001503','2021-11-03',-17.99,154.53,-2779.9947)
,('2022-10-24-004','PROD-000790','2022-10-24',-133.09,507.95,-67603.0655)
,('2023-04-25-004','PROD-000858','2023-04-25',-102.2,64.95,-6637.89)
,('2023-06-02-005','PROD-000858','2023-06-02',78.06,572.11,44658.9066)
,('2023-06-03-002','PROD-000858','2023-06-03',488.89,589.58,288239.7662)
,('2023-06-04-010','PROD-000858','2023-06-04',361.51,450.95,163022.9345)
,('2023-06-07-001','PROD-000858','2023-06-07',796.21,554.68,441641.7628)
,('2023-06-10-006','PROD-000858','2023-06-10',578.43,947.96,548328.5028)
,('2023-06-11-007','PROD-000858','2023-06-11',-92.17,60.94,-5616.8398)
,('2023-06-15-008','PROD-000858','2023-06-15',97.65,709.47,69279.7455)
,('2020-10-26-005','PROD-000536','2020-10-26',132.16,140.27,18538.0832)
,('2021-01-13-006','PROD-000174','2021-01-13',434.12,967.74,420115.2888)
,('2021-07-25-009','PROD-000174','2021-07-25',-308.81,1262.86,-389983.7966)
,('2021-10-06-010','PROD-001503','2021-10-06',-69.61,584.84,-40710.7124)
,('2022-05-20-011','PROD-001503','2022-05-20',-33.21,648.4,-21533.364)
,('2023-02-20-007','PROD-000790','2023-02-20',-629.76,340.04,-214143.5904)
,('2023-02-26-010','PROD-000790','2023-02-26',-640.88,648.62,-415687.5856)
,('2023-06-17-003','PROD-000858','2023-06-17',304.03,728.47,221476.7341)
,('2023-06-17-009','PROD-000858','2023-06-17',712.42,588.63,419351.7846)
,('2022-03-25-006','PROD-000536','2022-03-25',148.11,84.54,12521.2194)
,('2022-12-05-009','PROD-000790','2022-12-05',-280.92,305,-85680.6)
,('2023-04-01-005','PROD-000790','2023-04-01',-32.38,409.86,-13271.2668)
)n(trn,prod,tdate,qty,unitprice,extprice);
SELECT
CAST(n.prod as varchar(11)) as prod
,k.rn
,CAST(k.ID as varchar(14)) as ID
,ROUND(k.qty, 4) as qty
,ROUND(k.unitprice, 4) as unitprice
,ROUND(k.EXPRICE, 4) as exprice
,ROUND(k.INVONHAND, 4) as invonhand
,ROUND(k.INVCOST, 4) as invcost
,ROUND(k.COGS, 4) as cogs
,ROUND(k.GM, 4) as gm
,CAST(k.PURID as varchar(14)) as purid
,ROUND(k.PURQTY, 4) as purqty
,ROUND(k.PURPRICE, 4) purprice
INTO
#fifo
FROM
(SELECT DISTINCT PROD FROM #t)n
CROSS APPLY
wct.FIFOdet(REPLACE('SELECT trn,qty,extprice FROM #t WHERE prod = ''@prod'' ORDER BY tdate ASC, qty DESC','@prod',n.prod))k
SELECT
prod
,invonhand
,invcost
FROM
(
SELECT
ROW_NUMBER() OVER (PARTITION BY PROD ORDER BY PROD, RN DESC) as rnrev
,f.*
FROM
#fifo f
)n
WHERE
rnrev = 1
This produces the following result.
Note that 2 of the products have negative inventory balances, meaning that the sales exceeded the purchases. Since the inventory balance is less than zero the inventory cost is zero. In the next two examples we will show how to get the details for inventory balances greater than zero and less than zero.
Example #5
In this example, using the same tables that were created in Example #4, we show how to get the details of the outstanding inventory balances i.e., positive balances. For this example, those details are the product identifier, the transaction identifier, the transaction date, the original transaction quantity, the remaining transaction quantity, the original transaction amount, and the remaining transaction amount. This information might be used in the next inventory calculation after all the settled transactions have been archived. Additionally, we have included running totals of the inventory quantity and inventory cost which show that the amounts agree with the amounts in Example #4.
SET NOCOUNT ON;
DROP TABLE IF EXISTS #t;
DROP TABLE IF EXISTS #fifo;
SELECT
*
INTO
#t
FROM
(VALUES
('2020-11-18-002','PROD-000174','2020-11-18',223.18,921.06,205562.1708)
,('2022-04-15-009','PROD-000536','2022-04-15',187.13,73.54,13761.5402)
,('2022-04-17-002','PROD-000790','2022-04-17',50.43,307.51,15507.7293)
,('2020-09-03-007','PROD-000174','2020-09-03',235.1,570.99,134239.749)
,('2020-09-03-008','PROD-000536','2020-09-03',4.47,101.87,455.3589)
,('2021-05-19-001','PROD-000536','2021-05-19',-22.05,603.67,-13310.9235)
,('2021-12-05-008','PROD-001503','2021-12-05',-12.8,1449.14,-18548.992)
,('2022-03-30-003','PROD-000790','2022-03-30',-457.17,327.93,-149919.7581)
,('2022-07-18-008','PROD-000790','2022-07-18',-440.99,239.53,-105630.3347)
,('2022-07-18-010','PROD-000536','2022-07-18',-21.18,466.12,-9872.4216)
,('2020-12-29-008','PROD-000174','2020-12-29',-258.02,896.95,-231431.039)
,('2021-12-18-006','PROD-001503','2021-12-18',-62.66,119.22,-7470.3252)
,('2022-02-11-001','PROD-000174','2022-02-11',183.58,861.8,158209.244)
,('2022-02-12-004','PROD-000174','2022-02-12',251.96,751.35,189310.146)
,('2022-05-05-004','PROD-001503','2022-05-05',-44.83,464,-20801.12)
,('2023-05-23-001','PROD-000790','2023-05-23',-305.53,386.39,-118053.7367)
,('2020-07-17-003','PROD-000174','2020-07-17',-94.4,529.46,-49981.024)
,('2021-11-16-009','PROD-001503','2021-11-16',-34.56,1664.7,-57532.032)
,('2021-11-17-005','PROD-001503','2021-11-17',-49.98,1406.02,-70272.8796)
,('2021-11-19-007','PROD-001503','2021-11-19',-66.05,64.29,-4246.3545)
,('2022-03-08-007','PROD-000536','2022-03-08',28.94,69.75,2018.565)
,('2022-03-15-002','PROD-000536','2022-03-15',-1.98,570.72,-1130.0256)
,('2022-06-08-002','PROD-001503','2022-06-08',-20.28,305.35,-6192.498)
,('2022-06-13-003','PROD-000536','2022-06-13',128.65,46.35,5962.9275)
,('2021-08-08-004','PROD-000536','2021-08-08',152.55,85.52,13046.076)
,('2022-05-27-001','PROD-001503','2022-05-27',-11.62,1877.09,-21811.7858)
,('2022-08-25-006','PROD-000790','2022-08-25',-179.22,233.08,-41772.5976)
,('2021-05-20-005','PROD-000174','2021-05-20',507.47,808.33,410203.2251)
,('2021-11-03-003','PROD-001503','2021-11-03',-17.99,154.53,-2779.9947)
,('2022-10-24-004','PROD-000790','2022-10-24',-133.09,507.95,-67603.0655)
,('2023-04-25-004','PROD-000858','2023-04-25',-102.2,64.95,-6637.89)
,('2023-06-02-005','PROD-000858','2023-06-02',78.06,572.11,44658.9066)
,('2023-06-03-002','PROD-000858','2023-06-03',488.89,589.58,288239.7662)
,('2023-06-04-010','PROD-000858','2023-06-04',361.51,450.95,163022.9345)
,('2023-06-07-001','PROD-000858','2023-06-07',796.21,554.68,441641.7628)
,('2023-06-10-006','PROD-000858','2023-06-10',578.43,947.96,548328.5028)
,('2023-06-11-007','PROD-000858','2023-06-11',-92.17,60.94,-5616.8398)
,('2023-06-15-008','PROD-000858','2023-06-15',97.65,709.47,69279.7455)
,('2020-10-26-005','PROD-000536','2020-10-26',132.16,140.27,18538.0832)
,('2021-01-13-006','PROD-000174','2021-01-13',434.12,967.74,420115.2888)
,('2021-07-25-009','PROD-000174','2021-07-25',-308.81,1262.86,-389983.7966)
,('2021-10-06-010','PROD-001503','2021-10-06',-69.61,584.84,-40710.7124)
,('2022-05-20-011','PROD-001503','2022-05-20',-33.21,648.4,-21533.364)
,('2023-02-20-007','PROD-000790','2023-02-20',-629.76,340.04,-214143.5904)
,('2023-02-26-010','PROD-000790','2023-02-26',-640.88,648.62,-415687.5856)
,('2023-06-17-003','PROD-000858','2023-06-17',304.03,728.47,221476.7341)
,('2023-06-17-009','PROD-000858','2023-06-17',712.42,588.63,419351.7846)
,('2022-03-25-006','PROD-000536','2022-03-25',148.11,84.54,12521.2194)
,('2022-12-05-009','PROD-000790','2022-12-05',-280.92,305,-85680.6)
,('2023-04-01-005','PROD-000790','2023-04-01',-32.38,409.86,-13271.2668)
)n(trn,prod,tdate,qty,unitprice,extprice);
SELECT
CAST(n.prod as varchar(11)) as prod
,k.rn
,CAST(k.ID as varchar(14)) as ID
,ROUND(k.qty, 4) as qty
,ROUND(k.unitprice, 4) as unitprice
,ROUND(k.EXPRICE, 4) as exprice
,ROUND(k.INVONHAND, 4) as invonhand
,ROUND(k.INVCOST, 4) as invcost
,ROUND(k.COGS, 4) as cogs
,ROUND(k.GM, 4) as gm
,CAST(k.PURID as varchar(14)) as purid
,ROUND(k.PURQTY, 4) as purqty
,ROUND(k.PURPRICE, 4) purprice
INTO
#fifo
FROM
(SELECT DISTINCT PROD FROM #t)n
CROSS APPLY
wct.FIFOdet(REPLACE('SELECT trn,qty,extprice FROM #t WHERE prod = ''@prod'' ORDER BY tdate ASC, qty DESC','@prod',n.prod))k
SELECT
prod
,invonhand
,invcost
FROM
(
SELECT
ROW_NUMBER() OVER (PARTITION BY PROD ORDER BY PROD, RN DESC) as rnrev
,f.*
FROM
#fifo f
)n
WHERE
rnrev = 1
SELECT
n.PROD,
n.ID,
t.tdate,
t.qty as [Original Transaction Quantity],
INVONHAND as [Remaining Transaction Quantity],
t.extprice as [Original Transaction Cost],
INVCOST as [Remaining Transaction Cost],
SUM(INVONHAND) OVER (PARTITION BY n.PROD ORDER BY n.PROD, t.tdate ASC, t.qty DESC) as [Running Inventory Quantity],
SUM(INVCOST) OVER (PARTITION BY n.PROD ORDER BY n.PROD, t.tdate ASC, t.qty DESC) as [Running Inventory Cost]
FROM (
SELECT
p.PROD,
p.ID,
ROUND(p.qty+SUM(ISNULL(-s.PURQTY, 0)),4) AS INVONHAND,
ROUND(p.exprice+SUM(ISNULL(s.COGS,0)), 4) AS INVCOST
FROM
#fifo p
LEFT OUTER JOIN
#fifo s
ON
p.PROD = s.prod
AND p.id = s.purid
WHERE
p.qty > 0
GROUP BY
p.PROD,
p.ID,
p.qty,
p.exprice
)n
INNER JOIN
#t t
ON
n.ID = t.trn
WHERE
INVONHAND > 0
ORDER BY
n.prod,
t.tdate ASC,
t.qty DESC
This produces the following result.
Example #6
In this example, using the same tables that were created in Example #4, we show how to get the details of the outstanding unfilled order balances i.e., negative balances. For this example, those details are the product identifier, the transaction identifier, the transaction date, the original transaction quantity, the remaining transaction quantity, the original transaction amount, and the remaining transaction amount. This information might be used in the next inventory calculation after all the settled transactions have been archived. Additionally, we have included running totals of the sale quantity and sale amount which show that the amounts agree with the amounts in Example #4.
SET NOCOUNT ON;
DROP TABLE IF EXISTS #t;
DROP TABLE IF EXISTS #fifo;
SELECT
*
INTO
#t
FROM
(VALUES
('2020-11-18-002','PROD-000174','2020-11-18',223.18,921.06,205562.1708)
,('2022-04-15-009','PROD-000536','2022-04-15',187.13,73.54,13761.5402)
,('2022-04-17-002','PROD-000790','2022-04-17',50.43,307.51,15507.7293)
,('2020-09-03-007','PROD-000174','2020-09-03',235.1,570.99,134239.749)
,('2020-09-03-008','PROD-000536','2020-09-03',4.47,101.87,455.3589)
,('2021-05-19-001','PROD-000536','2021-05-19',-22.05,603.67,-13310.9235)
,('2021-12-05-008','PROD-001503','2021-12-05',-12.8,1449.14,-18548.992)
,('2022-03-30-003','PROD-000790','2022-03-30',-457.17,327.93,-149919.7581)
,('2022-07-18-008','PROD-000790','2022-07-18',-440.99,239.53,-105630.3347)
,('2022-07-18-010','PROD-000536','2022-07-18',-21.18,466.12,-9872.4216)
,('2020-12-29-008','PROD-000174','2020-12-29',-258.02,896.95,-231431.039)
,('2021-12-18-006','PROD-001503','2021-12-18',-62.66,119.22,-7470.3252)
,('2022-02-11-001','PROD-000174','2022-02-11',183.58,861.8,158209.244)
,('2022-02-12-004','PROD-000174','2022-02-12',251.96,751.35,189310.146)
,('2022-05-05-004','PROD-001503','2022-05-05',-44.83,464,-20801.12)
,('2023-05-23-001','PROD-000790','2023-05-23',-305.53,386.39,-118053.7367)
,('2020-07-17-003','PROD-000174','2020-07-17',-94.4,529.46,-49981.024)
,('2021-11-16-009','PROD-001503','2021-11-16',-34.56,1664.7,-57532.032)
,('2021-11-17-005','PROD-001503','2021-11-17',-49.98,1406.02,-70272.8796)
,('2021-11-19-007','PROD-001503','2021-11-19',-66.05,64.29,-4246.3545)
,('2022-03-08-007','PROD-000536','2022-03-08',28.94,69.75,2018.565)
,('2022-03-15-002','PROD-000536','2022-03-15',-1.98,570.72,-1130.0256)
,('2022-06-08-002','PROD-001503','2022-06-08',-20.28,305.35,-6192.498)
,('2022-06-13-003','PROD-000536','2022-06-13',128.65,46.35,5962.9275)
,('2021-08-08-004','PROD-000536','2021-08-08',152.55,85.52,13046.076)
,('2022-05-27-001','PROD-001503','2022-05-27',-11.62,1877.09,-21811.7858)
,('2022-08-25-006','PROD-000790','2022-08-25',-179.22,233.08,-41772.5976)
,('2021-05-20-005','PROD-000174','2021-05-20',507.47,808.33,410203.2251)
,('2021-11-03-003','PROD-001503','2021-11-03',-17.99,154.53,-2779.9947)
,('2022-10-24-004','PROD-000790','2022-10-24',-133.09,507.95,-67603.0655)
,('2023-04-25-004','PROD-000858','2023-04-25',-102.2,64.95,-6637.89)
,('2023-06-02-005','PROD-000858','2023-06-02',78.06,572.11,44658.9066)
,('2023-06-03-002','PROD-000858','2023-06-03',488.89,589.58,288239.7662)
,('2023-06-04-010','PROD-000858','2023-06-04',361.51,450.95,163022.9345)
,('2023-06-07-001','PROD-000858','2023-06-07',796.21,554.68,441641.7628)
,('2023-06-10-006','PROD-000858','2023-06-10',578.43,947.96,548328.5028)
,('2023-06-11-007','PROD-000858','2023-06-11',-92.17,60.94,-5616.8398)
,('2023-06-15-008','PROD-000858','2023-06-15',97.65,709.47,69279.7455)
,('2020-10-26-005','PROD-000536','2020-10-26',132.16,140.27,18538.0832)
,('2021-01-13-006','PROD-000174','2021-01-13',434.12,967.74,420115.2888)
,('2021-07-25-009','PROD-000174','2021-07-25',-308.81,1262.86,-389983.7966)
,('2021-10-06-010','PROD-001503','2021-10-06',-69.61,584.84,-40710.7124)
,('2022-05-20-011','PROD-001503','2022-05-20',-33.21,648.4,-21533.364)
,('2023-02-20-007','PROD-000790','2023-02-20',-629.76,340.04,-214143.5904)
,('2023-02-26-010','PROD-000790','2023-02-26',-640.88,648.62,-415687.5856)
,('2023-06-17-003','PROD-000858','2023-06-17',304.03,728.47,221476.7341)
,('2023-06-17-009','PROD-000858','2023-06-17',712.42,588.63,419351.7846)
,('2022-03-25-006','PROD-000536','2022-03-25',148.11,84.54,12521.2194)
,('2022-12-05-009','PROD-000790','2022-12-05',-280.92,305,-85680.6)
,('2023-04-01-005','PROD-000790','2023-04-01',-32.38,409.86,-13271.2668)
)n(trn,prod,tdate,qty,unitprice,extprice);
SELECT
CAST(n.prod as varchar(11)) as prod
,k.rn
,CAST(k.ID as varchar(14)) as ID
,ROUND(k.qty, 4) as qty
,ROUND(k.unitprice, 4) as unitprice
,ROUND(k.EXPRICE, 4) as exprice
,ROUND(k.INVONHAND, 4) as invonhand
,ROUND(k.INVCOST, 4) as invcost
,ROUND(k.COGS, 4) as cogs
,ROUND(k.GM, 4) as gm
,CAST(k.PURID as varchar(14)) as purid
,ROUND(k.PURQTY, 4) as purqty
,ROUND(k.PURPRICE, 4) purprice
INTO
#fifo
FROM
(SELECT DISTINCT PROD FROM #t)n
CROSS APPLY
wct.FIFOdet(REPLACE('SELECT trn,qty,extprice FROM #t WHERE prod = ''@prod'' ORDER BY tdate ASC, qty DESC','@prod',n.prod))k
SELECT
f.prod,
f.ID,
t.tdate,
t.qty as [Original Transaction Quantity],
f.qty as [Remaining Transaction Quantity],
t.extprice as [Original Transaction Amount],
f.exprice [Remaining Transaction Amount],
SUM(f.qty) OVER (PARTITION BY f.prod ORDER BY f.prod, f.rn) as [Running Sale Quantity],
SUM(f.exprice) OVER (PARTITION BY f.prod ORDER BY f.prod, f.rn) as [Running Sale Amount]
FROM
#fifo f
null">INNER JOIN
#t t
ON
f.ID = t.trn
WHERE
f.qty < 0
AND purid IS NULL
This produces the following result.
See Also