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

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

Related

Adding x work days onto a date in SQL Server?

I'm a bit confused if there is a simple way to do this.
I have a field called receipt_date in my data table and I wish to add 10 working days to this (with bank holidays).
I'm not sure if there is any sort of query I could use to join onto this table from my original to calculate 10 working days from this, I've tried a few sub queries but I couldn't get it right or perhaps its not possible to do this. I didn't know if there was a way to extract the 10th rowcount after the receipt date to get the calendar date if I only include 'Y' into the WHERE?
Any help appreciated.
This is making several assumptions about your data, because we have none. One method, however, would be to create a function, I use a inline table value function here, to return the relevant row from your calendar table. Note that this assumes that the number of days must always be positive, and that if you provide a date that isn't a working day that day 0 would be the next working day. I.e. adding zero working days to 2021-09-05 would return 2021-09-06, or adding 3 would return 2021-09-09. If that isn't what you want, this should be more than enough for you to get there yourself.
CREATE FUNCTION dbo.AddWorkingDays (#Days int, #Date date)
RETURNS TABLE AS
RETURN
WITH Dates AS(
SELECT CalendarDate,
WorkingDay
FROM dbo.CalendarTable
WHERE CalendarDate >= #Date)
SELECT CalendarDate
FROM Dates
WHERE WorkingDay = 1
ORDER BY CalendarDate
OFFSET #Days ROWS FETCH NEXT 1 ROW ONLY;
GO
--Using the function
SELECT YT.DateColumn,
AWD.CalendarDate AS AddedWorkingDays
FROM dbo.YourTable YT
CROSS APPLY dbo.AddWorkingDays(10,YT.DateColumn) AWD;

Using the result of a query to determine a value in a where clause in SQL?

So basically I've got a query where I want to filter using a date, however that date may change depending on what datas in the system.
If there's no records with a date of >='X', I want to use >='Y' instead
Currently I've got something like the following mess (Pseudocoded down to avoid using actual table names and such)
With a as (SELECT
count(column_id) as num
FROM tableA
WHERE ADate >= getdate() - 8)
,
b as (SELECT
case when num = '0' then getdate() - 15 else getdate() - 8 end as DateToUseInQuery
from A)
SELECT *
FROM tableB
Bunch of joins to other tables
WHERE BDate >= DateToUseInQuery
The general idea being is if there's no records for the week beforehand, use 2 weeks beforehand
I tried using a query within the where clause like:
WHERE BDate >= (SELECT DateToUseInQuery FROM b)
But the query ran for 11 minutes before I stopped it (Up from about 18 seconds before I tried to put this extra bit in)
I've been thinking about trying to set a variable as the date, but I can't do it in a CTE, and when I do it after, it breaks everything else.
So basically:
Is there an easier way to do this than the cack-handed way I'm trying?
If my way is fine, how can I pass that date properly into the WHERE clause?
You could try something like this. I am using a nested select and case statement to determine the number of days.
There may be a prettier way, but this works.
SELECT COUNT(column_id) AS num FROM TableA
WHERE ADate >=
DATEADD(Day,
(SELECT
CASE
WHEN EXISTS(
SELECT 1 FROM TableA
WHERE ADate >= DATEADD(Day,-8,GETDATE()))
THEN -8
ELSE -15
END AS 'dt')
,GETDATE());

SQL Server query to get next nearest date from recurring events

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

Get a Row if within certain time period of other row

I have a SQL statement that I am currently using to return a number of rows from a database:
SELECT
as1.AssetTagID, as1.TagID, as1.CategoryID,
as1.Description, as1.HomeLocationID, as1.ParentAssetTagID
FROM Assets AS as1
INNER JOIN AssetsReads AS ar ON as1.AssetTagID = ar.AssetTagID
WHERE
(ar.ReadPointLocationID='Readpoint1' OR ar.ReadPointLocationID='Readpoint2')
AND (ar.DateScanned between 'LastScan' AND 'Now')
AND as1.TagID!='000000000000000000000000'
I am wanting to do a query that will get the row with the oldest DateScanned from this query and also get another row from the database if there was one that was within a certain period of time from this row (say 5 seconds for an example). The oldest record would be relatively simple by selecting the first record in a descending sort, but how would I also get the second record if it was within a certain time period of the first?
I know I could do this process with multiple queries, but is there any way to combine this process into one query?
The database that I am using is SQL Server 2008 R2.
Also please note that the DateScanned times are just placeholders and I am taking care of that in the application that will be using this query.
Here is a fairly general way to approach it. Get the oldest scan date using min() as a window function, then use date arithmetic to get any rows you want:
select t.* -- or whatever fields you want
from (SELECT as1.AssetTagID, as1.TagID, as1.CategoryID,
as1.Description, as1.HomeLocationID, as1.ParentAssetTagID,
min(DateScanned) over () as minDateScanned, DateScanned
FROM Assets AS as1
INNER JOIN AssetsReads AS ar ON as1.AssetTagID = ar.AssetTagID
WHERE (ar.ReadPointLocationID='Readpoint1' OR ar.ReadPointLocationID='Readpoint2')
AND (ar.DateScanned between 'LastScan' AND 'Now')
AND as1.TagID!='000000000000000000000000'
) t
where datediff(second, minDateScanned, DateScanned) <= 5;
I am not really sure of sql server syntax, but you can do something like this
SELECT * FROM (
SELECT
TOP 2
as1.AssetTagID,
as1.TagID,
as1.CategoryID,
as1.Description,
as1.HomeLocationID,
as1.ParentAssetTagID ,
ar.DateScanned,
LAG(ar.DateScanned) OVER (order by ar.DateScanned desc) AS lagging
FROM
Assets AS as1
INNER JOIN AssetsReads AS ar
ON as1.AssetTagID = ar.AssetTagID
WHERE (ar.ReadPointLocationID='Readpoint1' OR ar.ReadPointLocationID='Readpoint2')
AND (ar.DateScanned between 'LastScan' AND 'Now')
AND as1.TagID!='000000000000000000000000'
ORDER BY
ar.DateScanned DESC
)
WHERE
lagging IS NULL or DateScanned - lagging < '5 SECONDS'
I have tried to sort the results by DateScanned desc and then just the top most 2 rows. I have then used the lag() function on DateScanned field, to get the DateScanned value for the previous row. For the topmost row the DateScanned shall be null as its the first record, but for the second one it shall be value of the first row. You can then compare both of these values to determine whether you wish to display the second row or not
more info on the lagging function: http://blog.sqlauthority.com/2011/11/15/sql-server-introduction-to-lead-and-lag-analytic-functions-introduced-in-sql-server-2012/

Latest date and time in SQL without ORDER BY

I'm trying to find a way to display the last event held (last date and time) in an events table whilst displaying all the columns for that event without using ORDER BY.
For example:
SELECT * from Events
where dateheld in (select max(dateheld) from events)
AND starttime in (select max(starttime) from events)
When I put MAX starttime, it displays nothing. When I put MIN starttime it works but displays the earliest time of that date and not the latest.
I guess you could print out your records, throw them down the stairs, and the ones that go farthest have the "lightest" dates. You cannot sort without order by. It's like wanting water that isn't wet. Unless your data naturally comes out in the order you want, you MUST sort.
Of course, if you want only the record that has the absolute most recent date, and don't need more than just that one record, then
SELECT yourdatetimefield, ...
FROM yourtable
HAVING yourdatetimefield = MAX(yourdatetimefield)
If you are only looking for the latest item:
EDIT gets a little more complicated when you have seperate date and time fields, but this should work. This is a ridiculous kludge for a situation where date and time should be stored in one field.
SELECT *
FROM (
SELECT *
FROM Events
WHERE dateTime = (SELECT MAX(dateheld) FROM Events)
) temp
WHERE starttime = (SELECT MAX(starttime) FROM (
SELECT *
FROM Events
WHERE dateTime = (SELECT MAX(dateheld) FROM Events)
) temp 2 )