I have a table with data like this:
CREATE TABLE Test
(CustName varchar(20), Country varchar(20), RecordedTime datetime, CurrNo tinyint);
INSERT INTO Test
You have a bunch of if/and/buts going on in your original request, but maybe having an ALTERNATE VIEW of the data might be a better solution that you just did not think of or have been offered, so I will.
Why have individual lines showing both the before and after, why not do on a single returned line. If there is no change, why show? Maybe that is a later question.
To get my solution, I have a simple WITH from the test data that I am using as a baseline for my query. You have your own CurrNo which may not always start with 1, and could even possibly skip a sequence number by some accident. So my WITH declaration gets a sequential row number by customer and ordered by the CurrNo. This will ALWAYS return per customer rows 1, 2, 3, 4 even if the CurrNo values may be 5, 8, 9, 11 (exaggerated starting number and accidental skipped values). You could even change the order by to the RecordedTime to ensure logging based on the DATE per customer activity.
;with baseData as
(
select
T.*,
ROW_NUMBER() OVER (PARTITION BY CustName ORDER BY CurrNo) AS CustOrder
from
Test T
)
So now, with the query. I have my first table which is the basis for finding any "changes" within the system. You will always start with these records. Apply a date restrictive filter as you need. The LEFT-JOIN will always be on the customer name PLUS whatever the row number is PLUS ONE joined to the NEXT of the same baseline data. So, if just looking at customer Alex and Jerry from your data, you would have the following
Customer Country Time CurrNo CustOrder
Alex Australia 2018-06-01 08:00:00 1 1
Alex China 2018-06-01 10:00:00 2 2
Alex India 2018-06-01 10:05:00 3 3
Alex Japan 2018-06-01 11:00:00 4 4
Jerry Cuba 2018-06-12 00:00:00 4 1
Jerry Brazil 2018-06-12 00:05:00 5 2
Jerry India 2018-06-12 00:10:00 7 3
Jerry USA 2018-06-12 00:15:00 9 4
So you can see the natural row number normalization between each. So Now, my left-join is by customer AND the CustOrder column which will not skip gaps, so I will get records like
Customer CustOrder NextCustOrder CurrNo NextCurrNo
Alex 1 2 1 1
Alex 2 3 2 2
Alex 3 4 3 3
Alex 4 (no 5th record) 4 4
Jerry 1 2 4 5
Jerry 2 3 5 7
Jerry 3 4 7 9
Jerry 4 (no 5th record) 9 (no next record)
Finally, I am getting the data from the first record which will always exist and IF A CORRESPONDING NEXT record exists, it will show that new changed TO value. That next record will be the next row and it's possible changed TO value and so on..
select
bd.CustName,
case when bd.CurrNo = 1 then 'ADD' else 'CHANGE' end as Audit,
bd.Country as CurrentValue,
bd.RecordedTime,
bdNext.Country as ChangedValue,
bdNext.RecordedTime ChangedTime,
bd.CurrNo,
bd.CustOrder
from
baseData bd
LEFT JOIN baseData bdNext
on bd.CustName = bdNext.CustName
AND bd.CustOrder +1 = bdNext.CustOrder;
CustName Audit CurrentValue RecordedTime ChangedValue ChangedTime CurrNo CustOrder
Alex ADD Australia 2018-06-01 08:00:00.000 China 2018-06-01 10:00:00.000 1 1
Alex CHANGE China 2018-06-01 10:00:00.000 India 2018-06-01 10:05:00.000 2 2
Alex CHANGE India 2018-06-01 10:05:00.000 Japan 2018-06-01 11:00:00.000 3 3
Alex CHANGE Japan 2018-06-01 11:00:00.000 NULL NULL 4 4
Jerry CHANGE Cuba 2018-06-12 00:00:00.000 Brazil 2018-06-12 00:05:00.000 4 1
Jerry CHANGE Brazil 2018-06-12 00:05:00.000 India 2018-06-12 00:10:00.000 5 2
Jerry CHANGE India 2018-06-12 00:10:00.000 USA 2018-06-12 00:15:00.000 7 3
Jerry CHANGE USA 2018-06-12 00:15:00.000 NULL NULL 9 4
If you don't want the "last value" for a record because no changes after, just change the LEFT JOIN to INNER JOIN to guarantee something changed after. But that would fail if you wanted to see all new "ADD" records without changes. You could apply that as a where clause something like
where
bd.CurrNo = 1
OR bdNext.CustOrder IS NOT NULL
Additionally you could add a date filter such as
where
bd.RecordedTime >= '2018-06-10'
AND ( bd.CurrNo = 1
OR bdNext.CustOrder IS NOT NULL )
As suggested in comment by Ronen Ariely, the above WHERE clause with the date would be applied to the WITH baseData as component, adding a
where
T.RecordedTime >= '2018-06-10'
to pre-filter the data before it gets to the rest of the join activity