Duration between 2 dates based on another column - sql

I currently have a table of data that shows different steps in a process, with a date/time each step was carried out.
enter image description here
What I'm looking to do is add a column that calculates the time in minutes between each step, however it has to relate to the claimID, so in the image shown I would be looking for difference between each step for the top 4 results (as they share the same claimID), then the following 6 results, etc.
Can anyone help? I'm using SQL Server

Depending on what version of SQL Server you are using you can either use a self join or the lag window function (this should work in SQL Server 2012+):
select
claimid
, statusid
, statussetdate
, coalesce(datediff(minute,
lag(statussetdate) over (partition by claimid order by statussetdate),
statussetdate
),0) as diff_in_minutes
from
your_table
order by
ClaimID
, StatusSetDate;

You can self join the table to itself using the Row_number to get the previous date and do a DateDiff on the 2 values..
;WITH cte AS
(
SELECT *, ROW_NUMBER() OVER (PARTITION BY ClaimID ORDER BY StatusSetDate) Rn
FROM ClaimStatus
)
SELECT curr.*,
ISNULL(DATEDIFF(minute, prev.StatusSetDate, curr.StatusSetDate),0)
FROM cte curr
LEFT JOIN cte prev ON curr.ClaimID = prev.ClaimID AND curr.Rn = prev.Rn + 1
ORDER BY curr.ClaimID, curr.StatusSetDate

Related

How to get previous record date for a group in a select query

I need to calculate the Prevdate as shown below without using CTE or temp tables. I tried using lead it applied for only one row above. Also the number of record for each group might vary. Can anyone suggest a solution here?
Below is the sample data:
create table #Sampledata
(
id int
,groupno int
,Date date
)
insert into #Sampledata values (
1,1,'1/2/2020'),
(2,2,'1/13/2020'),
(3,2,'1/13/2020'),
(4,2,'1/13/2020'),
(5,3,'1/24/2020')
Below is the expected output:
What you are calling the previous date is really the next date. That just helps understanding the question.
Unfortunately, SQL Server does not fully support range window frames, so window functions (at least in a simple manner) are not appropriate.
One method is using lead() in an aggregation subquery and joining the results in:
select sd.*, g.next_date
from sampledata sd join
(select groupno, lead(min(date)) over (order by groupno) as next_date
from Sampledata
group by groupno
) g
on sd.groupno = g.groupno;
Another option is cross apply:
select sd.*, x.next_date
from sampledata sd outer apply
(select top (1) min(sd2.date) as next_date
from sampledata sd2
where sd2.date > sd.date
) x;
Of course, if the groups really are sequentially enumerated, you can replace sd2.date > sd.date with sd2.groupno = sd.groupno + 1.
Here is a db<>fiddle.
try joining with one reduced this works only if groupno is continued.
select distinct s1.* , s2.PrevDate
from #Sampledata as s1
left join (
select groupno - 1 as num , [Date] as PrevDate
from #Sampledata
) as s2 on s1.groupno = s2.num
Edit: I caused a cartesian explosion so I just rammed a distinct in there to sort it out

Find the second largest value with Groupings

In SQL Server, I am attempting to pull the second latest NOTE_ENTRY_DT_TIME (items highlighted in screenshot). With the query written below it still pulls the latest date (I believe it's because of the grouping but the grouping is required to join later). What is the best method to achieve this?
SELECT
hop.ACCOUNT_ID,
MAX(hop.NOTE_ENTRY_DT_TIME) AS latest_noteid
FROM
NOTES hop
WHERE
hop.GEN_YN IS NULL
AND hop.NOTE_ENTRY_DT_TIME < (SELECT MAX(hope.NOTE_ENTRY_DT_TIME)
FROM NOTES hope
WHERE hop.GEN_YN IS NULL)
GROUP BY
hop.ACCOUNT_ID
Data sample in the table:
One of the "easier" ways to get the Nth row in a group is to use a CTE and ROW_NUMBER:
WITH CTE AS(
SELECT Account_ID,
Note_Entry_Dt_Time,
ROW_NUMBER() OVER (PARTITION BY AccountID ORDER BY Note_Entry_Dt_Time DESC) AS RN
FROM dbo.YourTable)
SELECT Account_ID,
Note_Entry_Dt_Time
FROM CTE
WHERE RN = 2;
Of course, if an ACCOUNT_ID only has 1 row, then it will not be returned in the result set.
The OP's statement "The row will not always be 2." from the comments conflicts with their statement "I am attempting to pull the second latest NOTE_ENTRY_DT_TIME" in the question. At a best guess, this means that the OP has rows with the same date, that could be the "latest" date. If so, then would simply need to replace ROW_NUMBER with DENSE_RANK. Their sampple data, however, doesn't suggest this is the case.
You can use window functions:
select *
from (
select
n.*,
row_number() over(partition by account_id order by note_entry_dt_time desc) rn
from notes n
) t
where rn = 2

Max() not filtering out MIN()

when I use run the query below, it returns duplicate StockNo's because some of them have duplicate WorkInProgress codes (FiWipStatus Code).
Is there a way to exclude the record based on the the MIN() on rowlastupdated?
as always, appreciate any help!
SELECT dbo.InventoryVehicle.StockNo, dbo.VehicleSales.FiWipStatusCode,
MAX(dbo.VehicleSales.RowLastUpdated) AS Expr1
FROM dbo.VehicleSales RIGHT OUTER JOIN
dbo.InventoryVehicle ON dbo.VehicleSales.StockNo = dbo.InventoryVehicle.StockNo
GROUP BY dbo.InventoryVehicle.StockNo, dbo.VehicleSales.FiWipStatusCode,
dbo.VehicleSales.RowLastUpdated
If I got it correctly, you need to get the records based on their last update date and time (which is RowLastUpdated). if so, you can do something like this :
SELECT
iv.StockNo
, vs.FiWipStatusCode
, vs.RowLastUpdated
FROM (
SELECT
iv.StockNo
, vs.FiWipStatusCode
, vs.RowLastUpdated
, ROW_NUMBER() OVER(PARTITION BY iv.StockNo ORDER BY vs.RowLastUpdated DESC) AS RN
FROM
VehicleSales vs
LEFT JOIN InventoryVehicle iv ON vs.StockNo = iv.StockNo
) D
WHERE
RN = 1
where ROW_NUMBER() will number the rows based on StockNo and order them based on RowLastUpdated in DESC. So, the first row of each distinct StockNo will be the MAX() datetime in your aggregation query. if you want to get the MIN() just change the order to ASC

How to select just the third or fourth row in SQL Server

I am having a little bit of trouble figuring out a way to select just the third or fourth row in a query I am writing, any help would be greatly appreciated.
This is an example of the code I came up with, this however only selects the first row.
Left Outer Join (select ap_attachments.ap_table_key, ap_description, ap_creation_date, ap_creation_time, ap_file_name, ap_attach_id
from ap_attachments
inner join (select Min(ap_attachment_id) ap_attach_id, ap_table_key
from ap_attachments
where ap_file_name like '%jpg%'
group by ap_table_key) C
On ap_attachments.ap_attachment_id = C.ap_attach_id) apImgThree_attach
On apImgTwo_attach.ap_table_key = order_link.to_order_id
You can do this with the ROW_NUMBER() function:
select ap_attachment_id, ap_table_key,ROW_NUMBER() OVER(PARTITION BY ap_table_key ORDER BY ap_attachment_id) AS RN
from ap_attachments
where ap_file_name like '%jpg%'
Then you can specify which row you'd like to return using the RN value. This may require some adapting depending on your source data, the DENSE_RANK() function may be more appropriate.
The ROW_NUMBER() function assigns a number to each row. PARTITION BY is optional, but used to start the numbering over for each value in that group, ie: if you PARTITION BY Some_Date then for each unique date value the numbering would start over at 1. ORDER BY of course is used to define how the counting should go, and is required in the ROW_NUMBER() function.
Look up the docs on lead and lag. You can also use the PARTITION clause to create the window within a specific date, for example;
declare #table table(
[flower] [sysname]);
insert into #table
([flower])
values (N'rose'),
(N'tulip'),
(N'chamomile'),
(N'lily');
select [flower] from #table order by [flower];
select [flower]
, lag ([flower]
, 1
, 0)
over (
order by [flower] desc) as [previous_flower]
, lead ([flower]
, 1
, 0)
over (
order by [flower] desc) as [next_flower]
from #table;

Calculating time between entries in sql

Guys i have a table that has a column named time. It capture the time of each record entry in to the database. I want to query and return another column displaying the duration between one entry and the entry before it. Example, if i store record for john today at 12:00 pm, and then Ali at 1:10 pm, i want another column that will show 01:10:00 (i.e HH:MM:SS).
I understand i can query each column number as follows.
SELECT ROW_NUMBER() OVER (ORDER BY [followuptime]) from [dbo].[FollowUp] .
i wanted to query the max row number AS follows but it fails and return error "windowed...."
SELECT MAX(ROW_NUMBER() OVER (ORDER BY [followuptime])) from [dbo].[FollowUp] .
I wanted to use the DATEDIFF(interval,start_time,end_time); function of sql , but as it is now, I am stuck. Please would appreciate your help or any alternative.
Since SQL-Server 2008R2 does not support LAG/LEAD you will need to do a self join using row_number to get the time from previous row:
WITH OrderedResults AS
( SELECT [id],
[followuptime],
[remark],
RowNumber = ROW_NUMBER() OVER (ORDER BY [followuptime])
FROM [dbo].[FollowUp]
)
SELECT a.ID,
a.FollowUpTime,
a.Remark,
PreviousTime = b.FollowUpTime,
MinutesDifference = DATEDIFF(MINUTE, b.FollowUpTime, a.FollowUpTime)
FROM OrderedResults a
LEFT JOIN OrderedResults b
ON b.RowNumber = a.RowNumber - 1
ORDER BY a.FollowUpTime;
Example on SQL Fiddle
You may not apply MAX to ROW_NUMBER. Use a CTE and query that.
;WITH MyCTE AS
(
SELECT ROW_NUMBER() OVER (ORDER BY [followuptime]) AS RowNum
FROM [dbo].[FollowUp]
)
SELECT MAX(RowNum)
FROM MyCTE