Reputation: 1202
I have the below table format
ID Status Date
16 In Review 2017-07-03 08:23:11.000
16 Approved 2017-07-03 08:23:20.000
16 Approved 2017-07-11 10:34:27.000
I am trying to get the time difference between In Review and Approved which should be 9 seconds..
This is a continuation of my previous Question where Gordon provided me an answer.
Here is the code for it
select avg(avg_bid_diff)
from (select bid, avg(diff*1.0) as avg_bid_diff
from (select bid, appid,
datediff(second, min(starttime), max(statustime)) as diff
from t
where appstatus in ('In Review', 'Approved')
group by bid, appid
having count(*) = 2
) ba
group by bid
) b;
The issue is that when it considers min and max I get the time difference between the 1st and the 3rd row and when only 2 status are there but what I need is the time Difference between the First In Review and the next Approved
Can someone please tell me how I should change the query to get the next Approved time difference.
Thanks
Upvotes: 0
Views: 126
Reputation: 336
It was bit tricky, but so far it seems to work good. The only limitation is that for each unique (BidID, AppID) pair there is NO or ONE record with status 'In Review'.
I have used whole different approach with chained CTE:
DECLARE @table TABLE
(
BidID int,
AppID int,
AppStatus nvarchar(20),
StatusTime DATETIME2
);
INSERT INTO @table (BidID, AppID, AppStatus, StatusTime)
VALUES
(1, 1, 'In Review', '2019-01-02 12:00:00'),
(1, 1, 'Approved', '2019-01-02 13:00:00'),
(1, 1, 'Approved', '2019-01-02 13:30:00'),
(1, 2, 'In Review', '2019-01-04 13:00:00'),
(1, 2, 'Approved', '2019-01-04 15:00:00'),
(2, 2, 'Approved', '2019-01-07 14:30:00'),
(2, 2, 'In Review', '2019-01-07 15:00:00'),
(2, 2, 'Approved', '2019-01-07 16:00:00'),
(3, 1, 'In Review', '2019-01-09 13:00:00'),
(4, 1, 'Approved', '2019-01-09 13:00:00');
;WITH OrderedRecords(BidID, AppID, AppStatus, StatusTime, [Order])
AS (
SELECT BidID
,AppID
,AppStatus
,StatusTime
, [Order] = ROW_NUMBER() OVER(PARTITION BY BidID, AppID ORDER BY StatusTime)
FROM @table
),
BidAverage(BidID, AveragePerBid)
AS (
SELECT OR1.BidID, AVG(CAST(DATEDIFF(HOUR, OR1.StatusTime, OR2.StatusTime) AS DECIMAL)) AS AveragePerBid
FROM OrderedRecords OR1
INNER JOIN OrderedRecords OR2
ON OR1.BidID = OR2.BidID AND OR1.AppID = OR2.AppID AND OR2.AppStatus = 'Approved' AND OR2.[Order] = OR1.[Order] + 1
WHERE OR1.AppStatus = 'In Review'
GROUP BY OR1.BidID
)
SELECT AVG(AveragePerBid) AS AveragePerTable
FROM BidAverage
AveragePerTable
---------------------------------------
1.250000
Here I try to explain the important steps:
Number records per BidID,AppID,StatusTime - this just numbers (orders) the records based on time the status appears and the numbering restarts per each (BidID, AppID) pair.
;WITH OrderedRecords(BidID, AppID, AppStatus, StatusTime, [Order])
AS (
SELECT BidID
,AppID
,AppStatus
,StatusTime
, [Order] = ROW_NUMBER() OVER(PARTITION BY BidID, AppID ORDER BY StatusTime)
FROM @table
)
SELECT * FROM OrderedRecords
BidID AppID AppStatus StatusTime Order
----------- ----------- -------------------- --------------------------- --------------------
1 1 In Review 2019-01-02 12:00:00.0000000 1
1 1 Approved 2019-01-02 13:00:00.0000000 2
1 1 Approved 2019-01-02 13:30:00.0000000 3
1 2 In Review 2019-01-04 13:00:00.0000000 1
1 2 Approved 2019-01-04 15:00:00.0000000 2
2 2 Approved 2019-01-07 14:30:00.0000000 1
2 2 In Review 2019-01-07 15:00:00.0000000 2
2 2 Approved 2019-01-07 16:00:00.0000000 3
3 1 In Review 2019-01-09 13:00:00.0000000 1
4 1 Approved 2019-01-09 13:00:00.0000000 1
Pick the right pairs of 'In Review', 'Approved' records
Basically the inner select of CTE BidAverage selects all 'InReview' records from the 'OrderedRecords' CTE and by joining the same table tries to find 'Approved' records with same BidID, AppID and Order which is 1 higher than the 'InReview' Order (that's the trick to get adjacent 'In reviw' and 'Approved'. The INNER join cuts off 'In review' records without 'Approved' and vice versa.
;WITH OrderedRecords(BidID, AppID, AppStatus, StatusTime, [Order])
AS (
SELECT BidID
,AppID
,AppStatus
,StatusTime
, [Order] = ROW_NUMBER() OVER(PARTITION BY BidID, AppID ORDER BY StatusTime)
FROM @table
)
SELECT OR1.BidID, OR1.AppID, OR1.AppStatus, OR1.StatusTime, OR1.[Order], OR2.AppStatus, OR2.StatusTime, OR2.[Order]
FROM OrderedRecords OR1
INNER JOIN OrderedRecords OR2
ON OR1.BidID = OR2.BidID AND OR1.AppID = OR2.AppID AND OR2.AppStatus = 'Approved' AND OR2.[Order] = OR1.[Order] + 1
WHERE OR1.AppStatus = 'In Review'
BidID AppID AppStatus StatusTime Order AppStatus StatusTime Order
----------- ----------- -------------------- --------------------------- -------------------- -------------------- --------------------------- --------------------
1 1 In Review 2019-01-02 12:00:00.0000000 1 Approved 2019-01-02 13:00:00.0000000 2
1 2 In Review 2019-01-04 13:00:00.0000000 1 Approved 2019-01-04 15:00:00.0000000 2
2 2 In Review 2019-01-07 15:00:00.0000000 2 Approved 2019-01-07 16:00:00.0000000 3
When you put all of this together (final script at the top of this answer), you get what you need. As I stated above the limitation here is that there is only one 'In Review' record per BidID and AppID. (But multiple 'Approved' can be present and 'In review' does not need to be the first one by time)
Upvotes: 1