SQL Server query to get next nearest date from recurring events - sql

This is my scenario. I have a table with FirstMaintenanceEventDate and some data repeating after certain days from FirstMaintenanceEventDate. What I need to find out through a SQL Server query is to get the nearest date of each row among them.
Ex: there is a data row FirstMaintenanceEventDate is last month and it will repeat after 40 days which is next month. Likewise there are a lot of events here. Some of them have FirstMaintenanceEventDate in the future. Out of all these items I need to get the nearest date for each row.
I could get the nearest date without considering repeating process.
This is my query
SELECT TOP 1 *
FROM FIS_MaintenanceEventInstance
WHERE VehicleName = '600-GUR'
AND FirstMaintenanceEventDate >= GETDATE()
ORDER BY FirstMaintenanceEventDate ASC
Need to update it to consider repeat events as I describe above. Probably something like this but this isn't correct.
SELECT TOP 1 *
FROM FIS_MaintenanceEventInstance
WHERE
VehicleName = '600-GUR'
AND FirstMaintenanceEventDate >= GETDATE()
AND CASE
WHEN FirstMaintenanceEventDate < GETDATE()
THEN (Getdate() + RecurringDays)
END
ORDER BY FirstMaintenanceEventDate ASC
Any suggestion would be appreciated.
NOTE: If you need more information please let me now.
EDITED
I have tried follow query as Jatin Patel suggested in his answer below.
SELECT TOP 1 *,
CASE WHEN FirstMaintenanceEventDate < GETDATE() THEN DateAdd(day,RecurringDays,FirstMaintenanceEventDate)
ELSE FirstMaintenanceEventDate END AS MaintenanceEventDate
FROM FIS_MaintenanceEventInstance
WHERE VehicleName ='600-GUR'
ORDER BY MaintenanceEventDate ASC
This is not working as expected. After calculate the repeat date (here it's MaintenanceEventDate) also should consider when get the nearest date. According to this query it is calculate repeated date (MaintenanceEventDate) if it is in past and return it without check with other dates in the table.

Try this,
SELECT TOP 1 *,
CASE WHEN FirstMaintenanceEventDate < GETDATE() THEN (Getdate()+RecurringDays) ELSE FirstMaintenanceEventDate END AS MaintenanceEventDate
FROM FIS_MaintenanceEventInstance
WHERE VehicleName ='600-GUR'
ORDER BY MaintenanceEventDate ASC

Related

How compare dates that are equal when one has time as well

I'm trying to compare dates and it looks like I'm doing it like examples online, but I only see the rows of dates returned when I do >= for the comparison. When I just use = it doesn't return anything.
This is my query with >= for the date comparison:
select *
from valhist_tbl --dmh
where
CRTUPDDT >= to_date('28-10-21','DD-MM-YY')
and metricvalue <> 'Device Found'
order by CRTUPDDT asc
I see a lot of this sort of thing returned:
CRTUPDDT METRICVALUE
28-OCT-21 12.00.00.069000000 AM NOT FOUND
28-OCT-21 12.00.00.071000000 AM NOT FOUND
...
I want it to do this: CRTUPDDT = to_date('28-10-21','DD-MM-YY')
but that doesn't return any rows.
I think the comparison as equals and not greater than has to do with the what is returned, but I'm not sure how to fix it. Also, I don't want to see duplicate lines returned, but there's so many that distinct makes it take forever.
This is a link I was looking at: date
Compare on a range over the entire day:
SELECT *
FROM valhist_tbl --dmh
WHERE CRTUPDDT >= DATE '2021-10-28'
AND CRTUPDDT < DATE '2021-10-28' + INTERVAL '1' DAY
AND metricvalue <> 'Device Found'
ORDER BY CRTUPDDT asc
You could also compare using TRUNC:
SELECT *
FROM valhist_tbl --dmh
WHERE TRUNC(CRTUPDDT) = DATE '2021-10-28'
AND metricvalue <> 'Device Found'
ORDER BY CRTUPDDT asc
However, if you have an index on CRTUPDDT then it would not be used in this latter query; you would need to have a function-based index on TRUNC(CRTUPDDT) instead.

How to look-up dates and find closest match

I have this problem using SQL where I want to find the closest matched date between two columns. Imagine this is my data-set:
'LY Date' is just last years date of 'Date' column I want to put into the new column 'Closest Date' which 'Date' that the 'LY Date', for each row, is closest to.
Example: the 22-02-2022 has last years date of 21-02-2021. This date is closest to the 15-02-2021 from 'Date' column so I put it in 'Closest Date'
I’ve referred to the columns as ‘DATE.DATE’ and ‘LYDATE.DATE’.
You can start from the LYDATE and obtain the top 1 record from DATE when DATE is sorted descending and only contains items less than ‘LYDATE’. You can then flip the DATE table and obtain the top 1 after filtering out those items less than LYDATE. This will give you the closest date that’s less than what we are looking for and the closest date that’s greater than what we are looking for.
I then calculate the date difference between those two limits to see which has smaller difference, and return the appropriate limit value as ClosestDate.
SELECT
CASE WHEN DATEDIFF(ns,lowerlimit.date, LYDate.date) < DATEDIFF(ns, upperlimit.date, LYDATE.date) THEN lowerlimit.date ELSE upperlimit.date END as ClosestDate
FROM LYDate
OUTER APPLY (SELECT TOP 1 DATE FROM DATE WHERE DATE.DATE < LYDATE.DATE ORDER BY DATE.DATE DESC) lowerlimit
OUTER APPLY (SELECT TOP 1 DATE FROM DATE WHERE DATE.DATE > LYDATE.DATE ORDER BY DATE.DATE ASC) upperlimit

Find closest date in SQL Server

I have a table dbo.X with DateTime column Y which may have hundreds of records.
My Stored Procedure has parameter #CurrentDate, I want to find out the date in the column Y in above table dbo.X which is less than and closest to #CurrentDate.
How to find it?
The where clause will match all rows with date less than #CurrentDate and, since they are ordered descendantly, the TOP 1 will be the closest date to the current date.
SELECT TOP 1 *
FROM x
WHERE x.date < #CurrentDate
ORDER BY x.date DESC
Use DateDiff and order your result by how many days or seconds are between that date and what the Input was
Something like this
select top 1 rowId, dateCol, datediff(second, #CurrentDate, dateCol) as SecondsBetweenDates
from myTable
where dateCol < #currentDate
order by datediff(second, #CurrentDate, dateCol)
I have a better solution for this problem i think.
I will show a few images to support and explain the final solution.
Background
In my solution I have a table of FX Rates. These represent market rates for different currencies. However, our service provider has had a problem with the rate feed and as such some rates have zero values. I want to fill the missing data with rates for that same currency that as closest in time to the missing rate. Basically I want to get the RateId for the nearest non zero rate which I will then substitute. (This is not shown here in my example.)
1) So to start off lets identify the missing rates information:
Query showing my missing rates i.e. have a rate value of zero
2) Next lets identify rates that are not missing.
Query showing rates that are not missing
3) This query is where the magic happens. I have made an assumption here which can be removed but was added to improve the efficiency/performance of the query. The assumption on line 26 is that I expect to find a substitute transaction on the same day as that of the missing / zero transaction.
The magic happens is line 23: The Row_Number function adds an auto number starting at 1 for the shortest time difference between the missing and non missing transaction. The next closest transaction has a rownum of 2 etc.
Please note that in line 25 I must join the currencies so that I do not mismatch the currency types. That is I don't want to substitute a AUD currency with CHF values. I want the closest matching currencies.
Combining the two data sets with a row_number to identify nearest transaction
4) Finally, lets get data where the RowNum is 1
The final query
The query full query is as follows;
; with cte_zero_rates as
(
Select *
from fxrates
where (spot_exp = 0 or spot_exp = 0)
),
cte_non_zero_rates as
(
Select *
from fxrates
where (spot_exp > 0 and spot_exp > 0)
)
,cte_Nearest_Transaction as
(
select z.FXRatesID as Zero_FXRatesID
,z.importDate as Zero_importDate
,z.currency as Zero_Currency
,nz.currency as NonZero_Currency
,nz.FXRatesID as NonZero_FXRatesID
,nz.spot_imp
,nz.importDate as NonZero_importDate
,DATEDIFF(ss, z.importDate, nz.importDate) as TimeDifferece
,ROW_NUMBER() Over(partition by z.FXRatesID order by abs(DATEDIFF(ss, z.importDate, nz.importDate)) asc) as RowNum
from cte_zero_rates z
left join cte_non_zero_rates nz on nz.currency = z.currency
and cast(nz.importDate as date) = cast(z.importDate as date)
--order by z.currency desc, z.importDate desc
)
select n.Zero_FXRatesID
,n.Zero_Currency
,n.Zero_importDate
,n.NonZero_importDate
,DATEDIFF(s, n.NonZero_importDate,n.Zero_importDate) as Delay_In_Seconds
,n.NonZero_Currency
,n.NonZero_FXRatesID
from cte_Nearest_Transaction n
where n.RowNum = 1
and n.NonZero_FXRatesID is not null
order by n.Zero_Currency, n.NonZero_importDate

Select statement to show next 'event' in the future

I am trying to retrieve the record of the next upcoming event, i have used a variety of different methods, but cannot seem to get the result. I need the event that is retrieved to be in the future,
For example if there was an event yesterday and there is one in three weeks time, i would like the record of the one in three weeks time, rather than yesterday.
The statement i have currently is:
SELECT TOP 1 *
FROM Events
WHERE StartDate <= DATEADD(day, DATEDIFF(day,0,getdate()), 0)
ORDER BY StartDate ASC
thanks
SELECT TOP 1 E.*
FROM Events E
WHERE E.StartDate > GetDate()
ORDER BY E.StartDate ASC
http://msdn.microsoft.com/en-us/library/ms188383.aspx

Get active rows between from and to date range inclusive of boundary

Table testTable has 4 columns
sessionid int
started datetime
ended datetime
SessionIsRunning bool - will be true if last session has not yet ended. Max only one record can be true at anytime since at the most only one session can be running. If no session is running then all records have this as false.
Given two dates say fromDate and toDate, how do I get the first session that started on or after fromDate and the last session that ended on or before toDate. Tricky condition is that if a session is in progress and it's start date >= fromDate we need this. I am guessing it might not be possible to get both the min and max session id in one sql statement and keep the code readable and easy to maintain. Two separate sql statements is ok. one to get min and one to get max. Then I can query rows using between min and max.
This last statement explains it in a different way. Get all sessions that started or was running and ended or was running between from/to dates thank you
After considering your edits and the comments regarding BETWEEN, this should give you the result set you need. It will pull any record where SessionIsRunning = true as well as sessions thats started AND ended in the date range.
SELECT * FROM testTable tt
WHERE (tt.started >= fromDate AND tt.started < DATEADD(DAY, 1, toDate)
AND tt.ended >= fromDate AND tt.ended < DATEADD(DAY, 1, toDate))
OR SessionIsRunning = true
ORDER BY tt.sessionid
Getting only the first and last value in a single query (because your question made me curious how to actually write this, even though that doesn't appear to be what you're really asking):
SELECT * FROM
(SELECT TOP 1 * FROM ATable ORDER BY AColumn ASC) first
UNION
SELECT * FROM
(SELECT TOP 1 * FROM ATable ORDER BY AColumn DESC) last