I want to use recursive query (it can be cte or anything) where I am trying to pull the executive report - where I input one employee name and I want all the hierarchy related to that employees starting with the top level emloyee (starting with CEO) and then going down.
For example:
If I input the employee name Celia, the report should look like:
CEO
Employees reporting to CEO , let's say MgrX
Employees reporting to MgrX- let's say MgrY
Employees reporting to MgrY - let's say MgrZ
All the Employees reporting to MgrZ including Celia (input parameter).
The query I am trying to use :
with cte1 as
(
select
pa.PERSNBR
,pa.AUTHCD
,pu.VALUE
,hr.File#
,hr.[Payroll Name]
,hr.[Reports To File#]
,hr.[Reports To Name]
,hr.[EMC #]
,hr.[EMC Name]
from
[DNA_Staging].[dbo].[PERSAUTH] pa
join [DNA_Staging].[dbo].[PERSEMPL] pe
on pa.PERSNBR = pe.PERSNBR
join [DNA_Staging].[dbo].[PERSUSERFIELD] pu
on pe.PERSNBR = pu.PERSNBR
and pu.USERFIELDCD = 'EFNR'
and GETDATE() < isnull(pe.inactivedate,getdate()+1)
join [HR_Staging].[dbo].[HR_EmployeeHierarchyStaging] hr
on pu.VALUE = substring(hr.File#,2,6)
or pu.VALUE = substring(hr.File#,3,6)
),
-- find all the data for input payroll name in the parameter
cte2 as (select *
FROM cte1 where [Payroll Name] = 'Acain, Celia T'),
A basic example for your question (you haven't provide any data samples or output examples, so...):
DECLARE #name nvarchar(20) = 'Darkwater'
;WITH emplevels AS (
SELECT *
FROM (VALUES
(1, 'CEO'),
(2, 'MgrX'),
(3, 'MgrY'),
(4, 'MgrZ')
) as t(eid, who)
),
people AS ( --people and there levels
SELECT *
FROM (VALUES
(1, 'Smith', 1),
(2, 'Wake', 2),
(3, 'Cartman', 3),
(4, 'Sanders', 4),
(5, 'MacCormic', 1),
(6, 'Malkovich', 2),
(7, 'Whatever', 2),
(8, 'Darkwater', 3),
(9, 'Leto', 4)
) as t(pid, name, eid)
),
dep AS ( --dependences of levels
SELECT *
FROM (VALUES
(1,1), --CEO - CEO
(1,2), --CEO - MgrX
(2,3), --MgrX - MgrY
(3,4) --MgrY - MgrZ
)as t(eid1,eid2)
),
hier as ( -- get the hierarchy
SELECT d.eid1,
d.eid2
FROM dep d
LEFT JOIN people p ON d.eid2 = p.eid
where name = #name
UNION ALL
SELECT d.eid1,
d.eid2
FROM dep d
INNER JOIN hier h ON d.eid2 = h.eid1
WHERE d.eid2 != d.eid1
)
--here comes heads and who there are
SELECT p.name AS Head,
e.who AS WhoIs
from hier h
LEFT JOIN people p ON p.eid = h.eid1
LEFT JOIN emplevels e ON e.eid = p.eid
ORDER BY e.eid
Result for Darkwater (he is MgrY). We have all MgrX and CEO's:
Head WhoIs
--------- -----
Smith CEO
MacCormic CEO
Wake MgrX
Malkovich MgrX
Whatever MgrX
(5 row(s) affected)
Related
I try to use the graph functionality in SQL Server. Now I have a problem with soft-delete.
I have the following graph
[1] -> [2] -> [9 (deleted)] -> [4]
When I run the following script
CREATE TABLE MyNode
(
[Id] [bigint] NOT NULL,
[IsDeleted] [bit] NOT NULL,
) AS NODE;
CREATE TABLE MyEdge
(
State [int] NOT NULL
) AS EDGE;
INSERT INTO MyNode (Id, IsDeleted)
VALUES (1, 0), (2, 0), (4, 0), (9, 1);
INSERT INTO MyEdge
VALUES
( (SELECT $node_id FROM MyNode WHERE Id = 1), (SELECT $node_id FROM MyNode WHERE Id = 2), 1),
( (SELECT $node_id FROM MyNode WHERE Id = 2), (SELECT $node_id FROM MyNode WHERE Id = 9), 1),
( (SELECT $node_id FROM MyNode WHERE Id = 9), (SELECT $node_id FROM MyNode WHERE Id = 4), 1)
;
SELECT
src.Id ID_SOURCE
, LAST_VALUE(trgt.Id) WITHIN GROUP (GRAPH PATH) AS ID_TARGET
, STRING_AGG(trgt.Id, '->') WITHIN GROUP (GRAPH PATH) AS ID_CHAIN
--, STRING_AGG(compare.State, '->') WITHIN GROUP (GRAPH PATH) AS STATE_CHAIN
--, STRING_AGG(trgt.IsDeleted, '->') WITHIN GROUP (GRAPH PATH) AS DELETED_CHAIN
FROM
MyNode AS src
, ( SELECT
*
FROM
MyEdge
WHERE
State = 1
) FOR PATH AS compare
, ( SELECT
*
FROM
MyNode
WHERE
IsDeleted = 0
) FOR PATH AS trgt
WHERE
MATCH ( SHORTEST_PATH( src(-(compare)->trgt)+ ) )
AND src.Id = 1;
SELECT
src.Id AS SOURCE_ID
, ed.State AS EDGE_STATE
, trgt.Id AS TARGET_ID
FROM
MyNode AS src
, MyEdge AS ed
, MyNode AS trgt
WHERE
MATCH( src-(ed)->trgt )
AND src.Id = 2;
DROP TABLE MyNode;
DROP TABLE MyEdge;
(Hint: this only works on SQL-Server 2019)
I get the following result
ID_SOURCE
ID_TARGET
ID_CHAIN
1
2
2
1
4
2->4
There is no edge 2->4 but 2->9->4. But the node 9 is deleted so it is used for the graph traversal but is suppressed in the output.
Is this a bug in SQL-Server or am I doing something wrong?
Or is there another way I should use soft delete with Graph-DB?
You could filter out the edges from/to soft-deleted nodes
....
(
SELECT e.*
FROM MyEdge as e
WHERE
e.State = 1
and exists(select * from MyNode as x where x.IsDeleted = 0 and x.$node_id = e.$to_id)
--and exists(select * from MyNode as x where x.IsDeleted = 0 and x.$node_id = e.$from_id)
) FOR PATH AS compare
....
Somehow the following query returns an error (after several secs of execution):
SELECT
src.Id ID_SOURCE
, LAST_VALUE(trgt.Id) WITHIN GROUP (GRAPH PATH) AS ID_TARGET
, STRING_AGG(trgt.Id, '->') WITHIN GROUP (GRAPH PATH) AS ID_CHAIN
--, STRING_AGG(compare.State, '->') WITHIN GROUP (GRAPH PATH) AS STATE_CHAIN
--, STRING_AGG(trgt.IsDeleted, '->') WITHIN GROUP (GRAPH PATH) AS DELETED_CHAIN
FROM
MyNode AS src
,
(
SELECT e.*
FROM MyEdge as e
WHERE
e.State = 1
and exists(select * from MyNode as x where x.IsDeleted = 0 and x.$node_id = e.$to_id)
--and exists(select * from MyNode as x where x.IsDeleted = 0 and x.$node_id = e.$from_id)
) FOR PATH AS compare
, ( SELECT
*
FROM
MyNode
WHERE
IsDeleted = 0
) FOR PATH AS trgt
WHERE
MATCH ( SHORTEST_PATH( src(-(compare)->trgt)+ ) )
...and the error goes away by appending a condition/reference to src table, which is always true :
AND src.Id = src.Id --or src.IsDeleted = src.IsDeleted
There is definitely something going wrong [Microsoft SQL Server 2019 (RTM-CU8-GDR) (KB4583459)]..
Incorporating an isDeleted flag into the edge table, and updating that flag whenever a corresponding (to/from) node is marked as soft-deleted, and using isDeleted on the edge table subquery, is the preferred way. We do not recommend directly comparing $node_id to $from_id other than implicitly through the MATCH function.
I need to use recursive with SQL Server, but i don't know how use it with my hierarchy tree.
I need some help for creating my query and know if it's possible with CTE Recursion.
My example :
I have two tables : piece (piece_id) and piece_equivalence(piece1_id, piece2_id)
First, i need to get all the piece from the first table :
SELECT DISTINCT p.record_id FROM piece p
Secondly, i need to check if the piece exists in the second table (piece1_id or piece2_id)
SELECT DISTINCT p.record_id
FROM piece p
inner join piece_equivalence pe
ON (pe.piece1_id = p.record_id OR pe.piece2_id = p.record_id)
Thirdly, if the piece exist, I need to check the piece1_id or piece2_id. This ID can have an equivalence too.
So I will check the second step too with my piece1_id or piece2_id.
Currently I did recursive calling the same function with parameter piece1 or piece2.
Graphical view with nodes :
piece_id
___/ \___
/ \
table : piece_equivalence piece1_id or piece2_id piece1_id or piece2_id
/ \ / \
table : piece_equivalence piece1_id or piece2_id same same same
Graphical with letters :
A
___/ \___ ________
/ \ \
B C D
/ \ / \ / \
D E F B E G
/ /
G H
A : piece
B, C, D, E, F, G, H are equivalences.
WARNING : I need to stock all piece with their equivalence in a temp table. For avoiding duplicate entry or infinity loop we must check this temp table the data exists or not.
EDIT :
I did this :
WITH pieces_CTE
AS
(
SELECT TOP 1 p.record_id as parent,
case when pe.piece1_id <> p.record_id then pe.piece1_id else pe.piece2_id end as enfant,
1 as level
FROM piece p
inner join piece_equivalence pe ON (pe.piece1_id = p.record_id OR pe.piece2_id = p.record_id) AND pe.pertinence = 100
AND pe.piece1_id <> pe.piece2_id
UNION ALL
SELECT c.parent, case when enfant.piece1_id <> c.parent then enfant.piece1_id else enfant.piece2_id end as enfant,
c.level+1
from pieces_CTE c
INNER JOIN piece_equivalence enfant ON (enfant.piece1_id = c.parent OR enfant.piece2_id = c.parent)
WHERE enfant.pertinence = 100
)
SELECT * from pieces_CTE ORDER BY parent,level,enfant
OPTION (MAXRECURSION 32767)
The statement terminated. The maximum recursion 100 has been exhausted
before statement completion.
But I have a large record on it, and my query has to much records, I think it's impossible to use CTE with many redundant cycles...
But why I have the same error with TOP 1 ?
Before you start with the Recursive CTE, You need to Know Few Things
You can't use DISTINCT or UNION
You Can't Use LEFT JOIN in the Recursive part of the CTE
You need to make sure the Recursion does not end in a Dead Lock. Otherwise by the Default Recursion count of 100, the CTE Will Terminate. Please see the below Example :
DECLARE #MyData TABLE (
SeqNo INT IDENTITY(1,1),
FullName VARCHAR(50),
ManagerId INT )
INSERT INTO #MyData (
FullName ) VALUES('CEO')
--Insert Sub Components
INSERT INTO #MyData (
FullName,
ManagerId ) SELECT
'Department Head 1',
ManagerId = SeqNo
FROM #MyData
WHERE FullName = 'CEO' UNION SELECT
'Department Head 2',
ManagerId = SeqNo
FROM #MyData
WHERE FullName = 'CEO' UNION SELECT
'Department Head 3',
ManagerId = SeqNo
FROM #MyData
WHERE FullName = 'CEO'
INSERT INTO #MyData (
FullName,
ManagerId ) SELECT
'Manager 1',
ManagerId = SeqNo
FROM #MyData
WHERE FullName = 'Department Head 1' UNION SELECT
'Manager 2',
ManagerId = SeqNo
FROM #MyData
WHERE FullName = 'Department Head 1' UNION SELECT
'Manager 3',
ManagerId = SeqNo
FROM #MyData
WHERE FullName = 'Department Head 3'
;WITH CTE AS (
SELECT
SeqNo,
FullName,
Manager = ISNULL(FullName,'')
FROM #MyData
WHERE ManagerId IS NULL
UNION ALL
SELECT
MD.SeqNo,
MD.FullName,
Manager = ISNULL(CTE.FullName,'')
FROM CTE
INNER JOIN #MyData MD
ON CTE.SeqNo = MD.ManagerId ) SELECT
*
FROM CTE
SeqNo FullName Manager
----------- -------------------------------------------------- --------------------------------------------------
1 CEO CEO
2 Department Head 1 CEO
3 Department Head 2 CEO
4 Department Head 3 CEO
7 Manager 3 Department Head 3
5 Manager 1 Department Head 1
6 Manager 2 Department Head 1
Not sure if this is possible but I'm trying to join to an alias column in SQL Server.
Is it possible to change the JOIN below?
JOIN
#LOGFILE ON #CSIQUESTIONLOG.LogSeqNo = #LOGFILE.Seq
AND #LOGFILE.Contcode = 'WCM'
to
JOIN
#LOGFILE ON #CSIQUESTIONLOG.LogSeqNo = #LOGFILE.[SEQ2]
AND #LOGFILE.Contcode = 'WCM'
So it joins to the SEQ2 column - not the SEQ column, and so I only have to run one query
Sample data below:
IF OBJECT_ID('tempdb..#CSIQUESTIONLOG') IS NOT NULL
DROP TABLE #CSIQUESTIONLOG
SELECT *
INTO #CSIQUESTIONLOG
FROM (VALUES ('BA', '2017-01-01','123451', '185', 2),
('BA', '2017-01-01','123452', '185', 4),
('BA', '2017-01-01','123453', '184', 1),
('BA', '2017-01-01','123454', '183', 3),
('BA', '2017-01-01','123455', '182', 5),
('BA', '2017-01-01','123456', '181', 0),
('BA', '2017-01-01','123457', '182', 1),
('BA', '2017-01-01','7684417', '180', 2)) d (Dealer, Created, Logseqno, CSIseqno, Answer)
IF OBJECT_ID('tempdb..#LOGFILE') IS NOT NULL
DROP TABLE #LOGFILE
SELECT *
INTO #LOGFILE
FROM (VALUES (7684417, 'BA', 498, 'WCM', 1261723),
(7669984, 'BA', 38, 'CSI', 1261723),
(7685141, 'BA', 400, 'WCM', 1261750),
(7686369, 'BA', 193, 'CSI', 1261750),
(7692571, 'BA', 401, 'WCM', 1262289),
(7700336, 'BA', 38, 'CSI', 1262289)) d (Seq, Dealer, OpNum, Contcode, ContSeqNo)
SELECT
a.*, x.Seq AS [SEQ2]
FROM
#LOGFILE a
OUTER APPLY
(SELECT Seq
FROM #LOGFILE b
WHERE b.ContSeqNo = a.ContSeqNo AND b.ContCode = 'CSI') x
Final query:
SELECT
#CSIQUESTIONLOG.Created, #CSIQUESTIONLOG.CSIseqno,
#LOGFILE.OpNum,
COUNT (*) AS TOTAL
FROM
#CSIQUESTIONLOG
JOIN
#LOGFILE ON #CSIQUESTIONLOG.LogSeqNo = #LOGFILE.Seq
AND #LOGFILE.Contcode = 'WCM'
GROUP BY
#CSIQUESTIONLOG.Created, #CSIQUESTIONLOG.CSIseqno, #LOGFILE.OpNum
Firstly, in your final query there ins no column Seq2. Those are two seperate queries, and thus, they can't interact with each other.
Without the expected result set, I've just chanegd the SQL to what I believe you're after. If it's not, post your expected result set.
SELECT QL.Created,
QL.CSIseqno,
LF2.OpNum, --Not sure if this should be LF1, or LF2. Guessed 2
COUNT (*) AS TOTAL
FROM #CSIQUESTIONLOG QL
JOIN #LOGFILE LF1 ON QL.LogSeqNo = LF1.Seq AND LF1.Contcode = 'WCM'
JOIN #LOGFILE LF2 ON LF1.ContSeqNo = LF2.ContSeqNo AND LF2.ContCode = 'CSI'
GROUP BY QL.Created, --You were completely missing your GROUP BY
QL.CSIseqno,
LF2.OpNum;
EDITED QUESTIONS:
I can't seem to figure out the conditional logic for my query.
I am certain that this is simple but I have been spinning my wheels on this one for too long - it is just one of those days.
Any help is always appreciated.
CURRENT QUERY:
SELECT
r.WidgetPK
,r.WidgetName
,r.WeightRateFlag [WeightRateFlag]
,r.Rate [Rate]
,r.Breakpoint [Breakpoint]
,MAX(ISNULL(f.ShippingFee,0)) [ShippingFee]
,MAX(ISNULL(f.OtherFee,0)) [OtherFee]
,MAX(r.weight) [Weight]
FROM
#Rates r
LEFT JOIN #Fees f ON f.WidgetPK = r.WidgetPK
I left out the GROUP BY for simplicity.
If the WeightRateFlag has a 1 in it in ANY row for each WidgetPK then all rows with a 0 will not be returned. If the WeightRateFlag has no rows with a 1 in it then ALL rows will be returned.
Sorry the original question wasn't clear - searches aren't helping and I asked a coworker. I think my problem may just be that I am asking the wrong question here and in my searches.
SELECT
r.WidgetPK
,r.WidgetName
,r.WeightRateFlag [WeightRateFlag]
,r.Rate [Rate]
,r.Breakpoint [Breakpoint]
,MAX(ISNULL(f.ShippingFee,0)) [ShippingFee]
,MAX(ISNULL(f.OtherFee,0)) [OtherFee]
,MAX(r.weight) [Weight]
FROM
#Rates r
LEFT JOIN #Fees f ON f.WidgetPK = r.WidgetPK
WHERE r.WeightRateFlag = 1
UNION ALL
SELECT
r.WidgetPK
,r.WidgetName
,r.WeightRateFlag [WeightRateFlag]
,r.Rate [Rate]
,r.Breakpoint [Breakpoint]
,MAX(ISNULL(f.ShippingFee,0)) [ShippingFee]
,MAX(ISNULL(f.OtherFee,0)) [OtherFee]
,MAX(r.weight) [Weight]
FROM
#Rates r
LEFT JOIN #Fees f ON f.WidgetPK = r.WidgetPK
WHERE r.WeightRateFlag = 0
AND NOT EXISTS (SELECT * FROM #rates r2 WHERE r2WeightRateFlag =1 AND r.WidgetName = r2.WidgetName)
A bit convoluted-looking, but CTEs can be extremely helpful. Plus they should work pretty well with the optimizer. Modify for the columns you need.
/* TEST DATA SETUP */
IF OBJECT_ID(N'tempdb..#t1') IS NOT NULL
BEGIN
DROP TABLE #t1
END
CREATE TABLE #t1 (WidgetPK int, col1 varchar(19), WeightRateFlag bit, ShippingFee money, OtherFee money, [Weight] int);
INSERT INTO #t1 (WidgetPK, col1, WeightRateFlag, ShippingFee, OtherFee, [Weight])
VALUES
(1, 'showme1', 1, 9, 1, 1)
, (1, 'noshow2', 0, 2, 9, 2)
, (1, 'noshow3', 0, 1, 2, 9)
, (2, 'showme1', 1, 9, 9, 9)
, (3, 'showme1', 0, 1, 9, 1)
, (3, 'showme2', 0, 9, 9, 9)
, (3, 'showme3', 0, 9, 1, 9)
;
/* QUERY STARTS HERE */
WITH cte1 AS (
SELECT x1.*
FROM (
SELECT #t1.WidgetPK, #t1.col1, #t1.WeightRateFlag, #t1.ShippingFee, #t1.OtherFee, #t1.[Weight]
, RANK() OVER (PARTITION BY #t1.WidgetPK ORDER BY #t1.WeightRateFlag DESC) AS rn
FROM #t1
) x1 WHERE x1.rn = 1
)
, cte2 AS (
SELECT cte1.WidgetPK
, MAX(cte1.ShippingFee) AS ShippingFee
, MAX(cte1.OtherFee) AS OtherFee
, MAX(cte1.[Weight]) AS [Weight]
FROM cte1
GROUP BY cte1.WidgetPK
)
SELECT cte1.WidgetPK, cte1.col1, cte1.WeightRateFlag, cte2.ShippingFee, cte2.OtherFee, cte2.[Weight]
FROM cte1
LEFT OUTER JOIN cte2 ON cte1.WidgetPK = cte2.WidgetPK
;
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 )