MSSQL: Select max date when a specific column was updated - sql-server

I need to return the last records which had a certain column updated.
The data is stored in 2 tables: ClientInfo and ClientInfoHistory both of them with a large amount of data, especially the history one (which keeps track on any changes on the main table ClientInfo). Even if only one column was updated in ClientInfo, a row with the version before that update will be inserted into ClientInfoHistory with audit info (the user and the date when that row was updated).
So I am interested in returning the max date when the Flag3 was changed for each ClientID + the user who changed that and the value of Flag3
The entire script should be in a stored proc avoiding perf issues.
My idea:
I create a temp table with the entire customer's history + actual data, then I compare the Flag3 to see when that flag was changed for each customer and throw it into another temp table along with the modifiedbyuserid and modifieddate. Then I select max(modifiedDate) for each customer.
The tables look like this:
create table dbo.ClientInfo(
ClientID int,
Flag1 bit,
Flag2 bit,
Flag3 bit,
CreatedByUserID int not null,
CreatedDate datetime not null default getdate(),
ModifiedByUserID int not null,
ModifiedDate datetime not null default getdate(),
constraint PK_UserInfo primary key (ClientID)
)
create table dbo.ClientInfoHistory(
ClientInfoHistoryID bigint identity not null,
ClientID int,
Flag1 bit,
Flag2 bit,
Flag3 bit,
CreatedByUserID int not null,
CreatedDate datetime not null,
HistoryStartModifiedByUserID int not null,
HistoryStartDate datetime not null,
HistoryEndModifiedByUserID int not null,
HistoryEndDate datetime not null,
constraint PK_ClientInfoHistory primary key (ClientInfoHistoryID)
)
CREATE NONCLUSTERED INDEX ix_ClientInfoHistory_ClientID_HistoryDates
on dbo.ClientInfoHistory (ClientID, HistoryStartDate, HistoryEndDate)
The temp table with the entire customer's history + actual data contains this:
SELECT c.ClientID
,c.Flag3
,c.ModifiedDate as HistoryStartDate
,'9999-12-31' as HistoryEndDate
,c.ModifiedByUserId as HistoryStartModifiedByUserID
FROM dbo.ClientInfo c with (nolock)
UNION
SELECT
ch.ClientID
,ch.Flag3
,ch.HistoryStartDate
,ch.HistoryEndDate
,ch.HistoryStartModifiedByUserID
FROM dbo.ClientInfoHistory ch with (nolock)
insert into dbo.ClientInfo (ClientID, Flag1, Flag2, Flag3, CreatedByUserID, CreatedDate, ModifiedByUserID, ModifiedDate)
values
(1,0,0,1,1234,'2019-05-29 04:57:13.360', 1111,'2019-07-01 08:35:13.360'),
(2,0,1,0,1233,'2019-03-12 04:57:13.360', 1233, '2019-03-12 04:57:13.360')
insert into dbo.ClientInfoHistory (ClientID, Flag1, Flag2, Flag3, CreatedByUserID, CreatedDate, HistoryStartModifiedByUserID,HistoryStartDate, HistoryEndModifiedByUserID, HistoryEndDate )
values
(1,1,1,1,1234,'2019-05-29 04:57:13.360', 1234, '2019-05-29 04:57:13.360', 4321,'2019-05-31 04:57:13.360'),
(1,0,1,1,1234,'2019-05-29 04:57:13.360', 4321,'2019-05-31 04:57:13.360', 9871,'2019-06-02 06:27:13.360'),
(1,0,1,0,1234,'2019-05-29 04:57:13.360',9871,'2019-06-02 06:27:13.360', 8765,'2019-06-21 11:06:13.360'),
(1,0,0,0,1234,'2019-05-29 04:57:13.360',8765,'2019-06-21 11:06:13.360', 9871,'2019-06-22 06:27:13.360')
(1,0,0,1,1234,'2019-05-29 04:57:13.360',9871,'2019-06-22 06:27:13.360', 4321,'2019-06-25 08:35:13.360'),
(1,0,1,1,1234,'2019-05-29 04:57:13.360',4321,'2019-06-25 08:35:13.360', 1111,'2019-07-01 08:35:13.360')
So for example above...The changes of that flag are:
ClientID,Flag3,ModifiedByUserID,ModifiedDate
1, 1, 1234, 29/05/2019
1, 0, 9871, 02/06/2019
1, 1, 9871, 22/06/2019***
2, 0, 1233, 12/03/2019***
and the final set of results should return only those rows marked with *** (the last version of Flag3 for each ClienID)
I am not so happy with the enitre process I chose and I am looking for another solution with a better performance. I would be really happy to hear some ideas from you guys

Following query must give you expected result
SELECT *
FROM (
SELECT *, ROW_NUMBER () OVER (PARTITION BY ch.ClientID ORDER BY ch.HistoryStartDate DESC) as Rn
FROM
(
SELECT c.ClientID
,c.Flag3
,c.ModifiedDate as HistoryStartDate
,'9999-12-31' as HistoryEndDate
,c.ModifiedByUserId as HistoryStartModifiedByUserID
-- ,ROW_NUMBER () OVER (PARTITION BY c.ClientID ORDER BY c.ModifiedDate DESC) as Rn
FROM dbo.ClientInfo c with (nolock)
UNION
SELECT
ch.ClientID
,ch.Flag3
,ch.HistoryStartDate
,ch.HistoryEndDate
,ch.HistoryStartModifiedByUserID
--,ROW_NUMBER () OVER (PARTITION BY ch.ClientID ORDER BY ch.HistoryStartDate DESC) as Rn
FROM dbo.ClientInfoHistory ch with (nolock)
) as CH
) AS T
WHERE T.Rn = 1

Your question was not exactly clear, but I believe this is what you are looking for.
You will probably want to change your indexing around a little to include Flag3, and depending on the size of your data you might consider indexing the temp table. But this is a quick and dirty query to get you started
;WITH CTE AS
(select t2.ClientID, MAX(HistoryStartDate) NotMatchDate
from #ClientInfo t1
INNER JOIN #ClientInfoHistory t2 on t1.ClientID = t2.ClientID and t1.Flag3 <> t2.Flag3
GROUP BY t2.ClientID
)
select t2.ClientID, MIN(HistoryStartDate) ModifiedDate
INTO #tmpClient
from #ClientInfo t1
INNER JOIN #ClientInfoHistory t2 on t1.ClientID = t2.ClientID and t1.Flag3 = t2.Flag3
INNER JOIN CTE t3 on t3.ClientID = t1.ClientID
WHERE t2.HistoryStartDate > t3.NotMatchDate
GROUP BY t2.ClientID
SELECT t1.ClientID, t1.Flag3,t1.HistoryStartModifiedByUserID ModifiedByUserID, t1.HistoryStartDate ModifiedDate
FROM #ClientInfoHistory t1
INNER JOIN #tmpClient t2 on t1.ClientID = t2.ClientID and t1.HistoryStartDate = t2.ModifiedDate
UNION ALL
SELECT t1.ClientID, Flag3,CreatedByUserID ModifiedByUserID,CreatedDate ModifiedDate
FROM #ClientInfo t1
LEFT JOIN #tmpClient t2 on t1.ClientID = t2.ClientID
WHERE t2.ClientID IS NULL
EDIT #2: Fixed for new rows

Related

SQL unpivot of multiple columns

I would like the following wide table to be unpivotted but only where a user has a true value against the field, along with the appropriate date.
Current State:
CUSTOMER_ID
First_Party_Email
Third_Party_Email
First_Party_Email_Date
Third_Party_Email_Date
40011111
1
1
2021-01-22 04:38:00.000
2021-01-17 06:38:00.000
50022222
NULL
1
NULL
2021-01-18 04:38:00.000
80066666
1
NULL
2021-01-24 05:38:00.000
NULL
_______________
_______________________
_______________________
_______________________________
_______________________________
Required State:
Customer_ID
Type
Value
Date
40011111
First_Party_Email
1
22/01/2021 04:38
40011111
Third_Party_Email
1
17/01/2021 06:38
50022222
Third_Party_Email
1
18/01/2021 04:38
80066666
First_Party_Email
1
24/01/2021 05:38
_______________________________________________________________________
Associated query to create table and my attempt that doesn't work:
create table Permissions_Obtained
(Customer_ID bigint
,First_Party_Email bit
,Third_Party_Email bit
,First_Party_Email_Date datetime
,Third_Party_Email_Date datetime
)
insert into Permissions_Obtained
(Customer_ID
,First_Party_Email
,Third_Party_Email
,First_Party_Email_Date
,Third_Party_Email_Date
)
VALUES
(40011111, 1, 1, '2021-01-22 04:38', '2021-01-17 06:38'),
(50022222, NULL, 1, NULL, '2021-01-18 04:38'),
(80066666, 1, NULL, '2021-01-24 05:38', null)
select *
from Permissions_Obtained
select
customer_id, Permission
from Permissions_Obtained
unpivot
(
GivenPermission
for Permission in (
First_Party_Email, Third_Party_Email
)
) unpiv1,
unpivot
(
GivenPermissionDate
for PermissionDate in (
First_Party_Email_Date, Third_Party_Email_Date
)
) unpiv2
where GivenPermission = 1
--drop table Permissions_Obtained
Any help would be massively appreciated. TIA
You cannot have multiple unpivots at the same time. Instead you can use Cross Apply or Inner join or union, union all or kind of joins depending on your requirement. I have added a sample answer for this using join and unpivot.
SELECT
unpvt.Customer_ID
, [Type]
, ISNULL(po.First_Party_Email ,po.Third_Party_Email) AS [Value]
,CASE WHEN unpvt.Type = 'First_Party_Email' THEN po.First_Party_Email_Date
ELSE po.Third_Party_Email_Date
END AS [Date]
FROM
(
SELECT
Customer_ID, First_Party_Email , Third_Party_Email
FROM Permissions_Obtained
) p
UNPIVOT
( [Value] FOR [Type] IN
(First_Party_Email , Third_Party_Email )
)AS unpvt
INNER JOIN Permissions_Obtained [po]
on [po].Customer_ID = unpvt.Customer_ID
When un-pivoting multiple columns, CROSS APPLY (VALUES is often the easiest and most effective solution.
It creates a virtual table per-row of the previous table, and therefore un-pivots it into separate rows.
SELECT
p.Customer_Id,
v.[Type],
v.Value,
v.Date
FROM Permissions_Obtained p
CROSS APPLY (VALUES
('First_Party_Email', p.First_Party_Email, p.First_Party_Email_Date),
('Third_Party_Email', p.Third_Party_Email, p.Third_Party_Email_Date)
) v([Type], Value, Date)
where v.Value IS NOT NULL;

Select distinct on declared table

I need to create concatenated query will get data with checking data in other tables.
Firstly I declared (and filled it) two tables with list of ID I'll check in other tables. On next step (2) I declared new table and filled it values I get by some checking params. This table contains only one column (ID).
After filling if I execute SELECT DISTINCT query from this table I'll get really unique ID. It's OK.
But on next step (3) I declare more one table and filling it by 3 tables. Of course it contains many duplicates. But I must create this query for checking and concatenating. And after that if I execute select distinct h from #NonUnicalConcat it returns many duplicate IDs.
What I did wrong? Where is an error?
USE CurrentBase;
--STEP 1
DECLARE #TempCSTable TABLE(TempTableIDColumn int);
INSERT INTO #TempCSTable VALUES('3'),('4');
DECLARE #TempCVTable TABLE(TempTableIDColumn int);
INSERT INTO #TempCVTable VALUES('2'),('13');
--STEP 2
DECLARE #TempIdTable TABLE(id int);
INSERT INTO #TempIdTable
SELECT TT1.ID
FROM Table1 AS TT1
LEFT OUTER JOIN Table2 ON Table2.ID = TT1.OptionalColumn
LEFT OUTER JOIN Table3 AS TT2 ON TT2.ID = TT1.OptionalColumn
LEFT OUTER JOIN Table4 AS TT3 ON TT3.ID = TT2.OptionalColumn
WHERE TT1.ValueDate > '2020-06-30'
AND TT1.ValueDate < '2020-08-04'
AND TT1.OptBool = '1'
AND TT1.OptBool2 = '0'
AND EXISTS
(
SELECT Table5.ID
FROM Table5
WHERE Table5.ID = TT1.ID
AND Table5.CV IN
(
SELECT TempTableIDColumn
FROM #TempCVTable
)
AND Table5.OptBool = '1'
)
AND EXISTS
(
SELECT Table6.ID
FROM Table6
WHERE Table6.IID = TT3.ID
AND Table6.CS IN
(
SELECT TempTableIDColumn
FROM #TempCSTable
)
);
SELECT distinct * FROM #TempIdTable;--this code realy select distinct
--STEP 3
DECLARE #NonUnicalConcat TABLE(c int, s int, h int);
INSERT INTO #NonUnicalConcat
SELECT TT1.TempTableIDColumn AS cc,
TT2.TempTableIDColumn AS ss,
TT3.id AS hh
FROM #TempCVTable AS TT1,
#TempCSTable AS TT2,
#TempIdTable AS TT3
WHERE NOT EXISTS
(
SELECT HID
FROM OtherBase.dbo.Table1
WHERE HID = TT3.id
AND CS = TT2.TempTableIDColumn
AND CV = TT1.TempTableIDColumn
);
select distinct h from #NonUnicalConcat;--this code return many duplicates

three tables join is not giving desired output

I have three tables:
1: Station_Details (master data table)
2: RF_Details
3: WL_Details
As mention in below image.
I need a to take data from all three table in to a output table
Master data from Station_details and other data from RF and WL tables.
If RF_Details and WL_Details tables are having same station id and same DateTime then in output table both rows details will show in one row.
If DateTime are different then it will appear in different rows.
I tried this sql query but I am not getting the same output like OUTPUT Table.
select rf.StationID, st.stationname, st.state,rf.rf,rf.cum-rf,wl.wl,DataTime
from [RF_Details] rf
join [WL_Details] wl
join Station_Details st
on rf.StationID = wl.StationId and
rf.DataRecieved=wl.DataRecieved and
st.stationid =rf.stationid and
st.stationid = wl.stationid;
But it didn't give the right number of rows and output.
Please help me for the same.
You should always put the join conditions along with the join itself. Also, adding the INNER is a practice I follow to ensure no extra records are returned.
SELECT rf.StationID, st.stationname, st.state, wl.DataRecieved, wl.waterlevel1,
rf.dailyrainfall, rf.cumrainfall
FROM [RF_Details] rf
INNER JOIN [WL_Details] wl
ON rf.StationID = wl.StationId AND
rf.DataRecieved=wl.DataRecieved
INNER JOIN Station_Details st
ON st.stationid =rf.stationid AND
st.stationid = wl.stationid;
declare #station_details table(id int, station_id varchar(10),station_name varchar(10),state varchar(10))
declare #rf_details table (id int, station_id varchar(10),rf int, cum_rf int, dt dateTIME)
declare #wl_details table (id int, station_id varchar(10),wl int,dt datetime)
insert into #station_details values
(1,'DEL-NDL','NDL','DEL'),
(2,'UP-LKO','LKO','UP'),
(3,'MP-BHP','BHP','MP'),
(4,'MHR-MUM','MUM','MHR')
INSERT INTO #RF_DETAILS VALUES
(1,'DEL-NDL',42,435,'2016-06-13 05:15:00'),
(2,'UP-LKO',0,501,'2016-06-13 05:15:00'),
(3,'MP-BHP',20,350,'2016-06-13 05:15:00'),
(4,'MHR-MUM',30,200,'2016-06-13 05:15:00'),
(5,'MHR-MUM',15,100,'2016-06-14 05:15:00'),
(6,'UP-LKO',50,350,'2016-06-13 05:15:00')
INSERT INTO #WL_DETAILS VALUES
(1,'DEL-NDL',25,'2016-06-13 05:15:00'),
(2,'UP-LKO',35,'2016-06-13 05:30:00'),
(3,'MP-BHP',46,'2016-06-13 05:45:00'),
(4,'MHR-MUM',20,'2016-06-13 05:15:00'),
(5,'MHR-MUM',15,'2016-06-14 05:15:00'),
(6,'UP-LKO',60,'2016-06-13 05:15:00')
;with cte as
(
SELECT case
when rf.dt = wl.dt then 'Y'
else 'N'
end as matched,
rf.id as id,rf.station_id as stationid,rf.rf as rf , rf.cum_rf as cumrf , rf.dt as rfdt,
wl.id as wlid, wl.station_id ,wl.wl ,wl.dt as wldte,
rf.station_id as station,rf.dt as rfdte
FROM #RF_DETAILS RF
JOIN #WL_DETAILS WL ON rf.id = wl.id and RF.STATION_ID = WL.STATION_ID
)
select row_number() over (order by s.id) newid,
s.id,s.station_id,sd.station_name,sd.state,s.rf,s.cumrf,s.wl,
case
when s.srce = 'L' then s.rfdte
else s.wldte
end as 'Date'
from
(
select 'L' as srce,cte.id,cte.station_id,cte.rf,cte.cumrf, cte.wl as wl, cte.rfdte,cte.wldte from cte where cte.matched = 'Y'
union
select 'L' as srce,cte.id,cte.station_id,cte.rf,cte.cumrf, null as wl, cte.rfdte,cte.wldte from cte where cte.matched = 'N'
union all
select 'R' as srce,cte.id * 10,cte.station_id,null,null, cte.wl as wl, cte.rfdte,cte.wldte from cte where cte.matched = 'N'
) s
join #station_details sd on sd.station_id = s.station_id
order by s.id
You should redesign your database: right now you have a secondary key in RF_Details and WL_Details - DateTime. Which plays a role of a foreign key between them. Which is no good and will continue confusing you every time you need to join those table or collect corresponding data.
There should be another table like Station_Records which will store a row per every record for that station: (id, station_id, record_date_time). RF and WL rows if any should refer this table instead of referring Station_Details with station_id and one another with datetime.
With current structure you need to do full join of RF and WL to get both: matching by datetime - in same row, not matching - in separate rows.
select sd.station_name, Station_Records.*
from Station_Details sd
inner join
(
select
IsNull(rf.station_id, wl.station_id) station_id,
IsNull(rf.DataRecieved, wl.DataRecieved) DataRecieved,
rf.rf, rf.cum-rf, wl.wl
from [RF_Details] rf
full join [WL_Details] wl
on wl.station_id = rf.station_id
and wl.DataRecieved = rf.DataRecieved
) Station_Records
on Station_Records.station_ud = sd.station_id
concrete implementation may consist of OUTER APPLY or even be without any subqueries - it does not really matter currently.
Modify your table structure and you will always know all matching records:
select
sd.station_id, sd.station_name,
sr.DataRecieved
rf.rf, rf.cum-rf,
wl.wl
from Station_Details sd
inner join Station_Records sr
on sr.station_id = sd.station_id
left join RF_Details rf
on rf.record_id = sr.record_id
left join WL_Details wl
on wl.record_id = sr.record_id

using WHERE clause in INSERT trigger SQL

I am trying to insert a sum of prices from another table.
INSERT INTO Invoice_Of_Supplier (OrderSupplierID, PaymentStatus, Cost)
VALUES (
( SELECT OrderSupplierID FROM inserted),
0,
(SELECT SUM([Price(RUB)]) FROM Car
JOIN OrderOfSupplier_Car AS osc ON osc.CarID=Car.CarID
where osc.OrderSupplierID = (select OrderSupplierID from inserted)))
I have a Car table with fields price , CarID etc;
Order_Of_Supplier table with fields OrderSupplierID, SupplierID;
And Order_Of_Supplier_Car table in which there is a number of cars for each order( fields are CarID, OrderSupplierID)
I need to insert a row in table 'InvoiceOfSupplier' with fields 'OrderSupplierID', PaymentStatus and Cost.
OrderSupplierID and PaymentStatus are ok, but Cost is NULL and I cant understand why.
When i change on osc.OrderSupplierID = 2(getting OrderSupplierID directly) it doesn't work niether.
it Only works, when i remove all conditions like 'WHERE', but in this case it gets the 'Price(RUB)' of all orders, not the one I need.
EDIT:
The problem is that at the moment data was inserted in Order_Of_Supplier there was no data in Order_Of_Supplier_Car.
Try something like this:
INSERT INTO Invoice_Of_Supplier (OrderSupplierID, PaymentStatus, Cost)
VALUES (
( SELECT OrderSupplierID FROM inserted),
0,
(SELECT SUM(column_name) FROM Car
where Car.CarID = OrderOfSupplier_Car.CarID
and OrderOfSupplier_Car.OrderSupplierID in (select OrderSupplierID from inserted))
Why don't you just select from inserted?
INSERT INTO dbo.Invoice_Of_Supplier (OrderSupplierID, PaymentStatus, Cost)
SELECT
i.OrderSupplierID,
0,
SUM(osc.[Price(RUB)])
FROM inserted i
inner join dbo.OrderOfSupplier_Car osc
on osc.OrderSupplierID = i.OrderSupplierID
inner join dbo.Car c
ON c.CarID = osc.CarID
group by i.OrderSupplierID
and I reckon you don't need that join to Car at all
Some questions to you: is this after or instead of trigger? On which table is it?

Multiple value IF statement, to show in select

Any help appreciated,
the code below is from a database which someone made, every time a receipt is made a unique receipt id is issued. same when a reversal is made a new receipt is issued. what links the two are the pay in number. If a reverse is issued, the reverse flag changes on the old receipt to Y and the new one says N. i have my query that select Minimum date and Max data, for receipts returned will have a much later date that when it was first created. The issue is when there is no reverse, it still pulls information as the min and max date are the same. I am fully aware that i need an if statement, but have no idea how to do it since i am new to Databases.
Select distinct r.receipt_date, r.receipt_no, r.doc_no as Payin_No,r.trans_amt,l.location_desc, ct.charge_type_desc,
(select un.first_name + ' ' + un.last_name)as cashier,
r.payee, r.comments, r.reverse_flag, ret1.returned_by, ret1.return_date
from Cashier..receipts as r
inner join Cashier..location as l on r.location_id=l.location_id
inner join [Cashier].[dbo].[charge_type] as ct on ct.charge_type_no=r.charge_type_no
inner join Cashier..user_name as un on un.user_name=(UPPER(r.created_by))
inner join (
select receipt_no as Return_Receipt ,
(select un2.first_name + ' ' + un2.last_name) as returned_by,
created_date as return_date, doc_no as Payin_no,
r1.reverse_flag
from Cashier..receipts as r1
inner join Cashier..user_name as un2 on un2.user_name=(UPPER(r1.created_by))
where doc_no = r1.doc_no
and created_date = (select MAX(created_date)
from Cashier..receipts where doc_no = r1.doc_no)) as ret1
on (ret1.Payin_no=r.doc_no)
where r.receipt_date = (select MIN(r1.receipt_date) from Cashier..receipts as r1 where r1.receipt_no = r.receipt_no )
Issue i am having, the return by is the same as created
Desired result
Is this basically what you're trying to do?
-- test data creation, for me
create table receipts (receipt_no int, receipt_date datetime, doc_no int, reverse_flag char(1), returned_by varchar(10), create_date datetime, created_date datetime)
insert into receipts values (1, '1/1/2016', 12345, 'Y', 'John', null, '1/1/2016')
insert into receipts values (2, '2/15/2016', 12345, 'N', null, '2/15/2016', '2/15/2016')
SELECT r.receipt_date, r.receipt_no, r.doc_no, r.reverse_flag, ret1.return_date
FROM receipts r
INNER JOIN (
SELECT doc_no, create_date as return_date
FROM receipts
WHERE reverse_flag = 'N')ret1 on r.doc_no = ret1.doc_no and ret1.return_date > r.receipt_date
WHERE r.reverse_flag = 'Y' and r.doc_no = 12345
If that's your goal, I think you just tack this on to the very end of your query:
and r.receipt_date < ret1.return_date
Edit: Based on your update, I think tack this onto the end:
and convert(date, r.receipt_date) < convert(date, ret1.return_date)
I'm still really not sure what you want.
select *
from ( select doc_no, min(receipt_date) as min_receipt_date
from receipts group by doc_no ) as min_receipt
left outer join ( select doc_no, max(receipt_date) as max_receipt_date
from receipts group by doc_no) as max_receipt
on min_receipt.doc_no = max_receipt.doc_no and
min_receipt.min_receipt_date <> max_receipt.max_receipt_date
for
insert into receipts values (1, '2016-01-01', 12345, 'Y', 'John', null, '2016-01-01');
insert into receipts values (2, '2016-03-15', 12345, 'N', null, '2016-03-15', '2016-03-15');
insert into receipts values (3, '2016-03-15', 123667, 'N', null, '2016-03-15', '2016-03-15');
yields
doc_no min_receipt_date doc_no max_receipt_date
12345 January, 01 2016 00:00:00 12345 March, 15 2016 00:00:00
123667 March, 15 2016 00:00:00 (null) (null)
but it assumes that the return date will never be the same as the original receipt date. I also left off the Y and N flags because I don't see how it's necessary if the min date is always the original purchase date. The other answer here uses the created_date but in your screenshot of the table data, you only show one date so I wrote it assuming only one date (the receipt date). I tested that on MySQL because SQLFiddle was hating on my SQL Server syntax for inserts and I don't have another way to test right now.
This is what i was looking for, figured it out. Thank you Max for opening insights on how i could tackle the problem.
Select distinct r.receipt_date, r.receipt_no, r.doc_no as Payin_No,r.trans_amt,l.location_desc, ct.charge_type_desc,
(select un.first_name + ' ' + un.last_name)as cashier,
r.payee, r.comments, r.cost_centre, r.item, r.programme, r.activity, r.btl_sof, r.reverse_flag, --, ret1.returned_by, ret1.return_date
(case when r.reverse_flag = 'Y' then (select (un2.first_name + ' ' + un2.last_name)from Cashier..receipts as r1
inner join Cashier..user_name as un2 on un2.user_name=(UPPER(r1.created_by)) where created_date = (select MAX(created_date)
from Cashier..receipts where doc_no = r.doc_no)) end ) as returned_by ,
(case when r.reverse_flag = 'Y' then (select created_date from Cashier..receipts as r1
inner join Cashier..user_name as un2 on un2.user_name=(UPPER(r1.created_by)) where created_date = (select MAX(created_date)
from Cashier..receipts where doc_no = r.doc_no)) end ) as returned_date
from Cashier..receipts as r
inner join Cashier..location as l on r.location_id=l.location_id
inner join [Cashier].[dbo].[charge_type] as ct on ct.charge_type_no=r.charge_type_no
inner join Cashier..user_name as un on un.user_name=(UPPER(r.created_by))
where r.receipt_date = (select MIN(r1.receipt_date) from Cashier..receipts as r1 where r1.receipt_no = r.receipt_no )

Resources