-- set up data
DECLARE @t TABLE(nominalCode VARCHAR(10) NOT NULL, monthYear DATE NOT NULL, VALUE INT NOT NULL)
INSERT @t VALUES('AB10000','20120101',1000),
('AB10001','20120101',5000),
('AB10000','20120201',2000),
('AB10001','20120201',4000)
-- process query
;WITH CTE(nominalCode, monthYear, VALUE, row_num) AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY nominalCode ORDER BY monthYear)
FROM @t)
SELECT A.nominalCode, A.monthYear Start, B.monthYear Finish, A.value-B.value Diff
FROM CTE A
INNER JOIN CTE B ON A.nominalCode=B.nominalCode AND A.row_num=B.row_num-1
-- insert new value
INSERT @t VALUES('AB10000','20120301',5000)
-- same query
;WITH CTE(nominalCode, monthYear, VALUE, row_num) AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY nominalCode ORDER BY monthYear)
FROM @t)
SELECT A.nominalCode, A.monthYear Start, B.monthYear Finish, A.value-B.value Diff
FROM CTE A
INNER JOIN CTE B ON A.nominalCode=B.nominalCode AND A.row_num=B.row_num-1I'm using date to store month/year rather than a number or character string, and I strongly recommend you do the same. Anything resembling a date should be stored that way to prevent invalid dates from being entered and to ensure they order/sort correctly.