TSQL Search Query between two dates - sql-server

I am having a little trouble figuring out how to write a query that seems pretty straight forward.
The problem is in my WHERE clause. There are two fields in my table. A timestamp for when the task has started startTime and a timestamp for when the task was completed endTime/ Both of these fields are Datetime.
In my UI, I allow the person to select a Start Date and End Date and their filtering option.
The date logic should be as follows:
Everything where the StartTime is >= #startDate but < #endDate and the EndTime is <=#endDate but > #startDate.
I have done date ranges before using a single date in the database but not multiple so I am confused.
Any thoughts?
-- Fetch our data
SELECT [recordID],
[ItemID],
[QID],
[NTID],
[EmpID],
[FirstName],
[LastName],
[SupQID],
[SupEmpID],
[SupFirstName],
[SupLastName],
[Location],
[Department],
[Skillset],
[BudgetMarket],
CONVERT (VARCHAR (20), [startTime], 100) AS startTime,
CONVERT (VARCHAR (20), [endTime], 100) AS endTime,
COALESCE (DATEDIFF(SECOND, startTime, endTime), 0) AS totalTimeSeconds
FROM itemTracker_records
WHERE (#employee IS NULL OR (QID = #employee))
AND (#supervisor IS NULL OR (supQID = #supervisor))
AND CAST(endTime as Date) >= #startDate AND CAST(endTime as Date) < #endDate
FOR XML PATH ('results'), TYPE, ELEMENTS, ROOT ('root');

Shouldn't it be as simple as :
WHERE (StartTime >= #startDate AND #startDate < #endDate )
AND (EndTime <= #endDate AND #endDate > #startDate)

Or, slightly shorter:
WHERE StartTime between #startDate AND #endDate
AND EndTime between #startDate AND #endDate

Assuming "good" data, i.e. tasks always end after they start and the user supplied range is valid:
where startTime >= #StartDate and endTime <= #EndDate
As long as that is true then the task time span must be contained within the user specified range.
Note that a common problem is attempting to find date/time values between a pair of dates. To include all times on the last day it is necessary to add one day to #EndDate and remove equality from the comparison.

Related

Conditional Where clause in SQL query if one or both date range parameters are null

I am not sure if I am asking the right question here, but I will try to explain what I need. I need to write a SQL query with a #StartDate and an #EndDate parameter.
If both parameters have a value, then my where clause will need to include:
WHERE CAST(CreatedDate AS date) BETWEEN #StartDate AND #EndDate
If #EndDate is null, then it should be:
WHERE CAST(CreatedDate AS date) = #StartDate
If both or null then the date should not be a part of the WHERE clause at all.
I have tried a couple of things like:
DECLARE #StartDate varchar(20) = '12-02-2020'
DECLARE #EndDate varchar(20) = ''
SELECT *
FROM [dbo].[tbl_Support_Requests]
WHERE
CAST(CreatedDate AS date) >= ISNULL(#StartDate, CreatedDate)
AND CAST(CreatedDate AS date) <= ISNULL(#EndDate, CreatedDate)
and also:
DECLARE #StartDate varchar(20) = '12-02-2020'
DECLARE #EndDate varchar(20) = ''
SELECT *
FROM [dbo].[tbl_Support_Requests]
WHERE (#EndDate IS NULL
AND (CAST(CreatedDate AS date) >= #StartDate)
OR (#EndDate IS NOT NULL
AND CAST(CreatedDate AS date) >= #StartDate
AND CAST(CreatedDate AS date) <= #EndDate))
I am hoping there is a way to do this without the need for dynamic SQL. Any assistance is greatly appreciated.
Your first variant was quite close. Rather than using the proprietary ISNULL, we can use the SQL standard COALESCE instead. Which supports more than two arguments:
Declare #StartDate datetime2 = '20200212'
Declare #EndDate datetime2 = null
SELECT *
FROM [dbo].[tbl_Support_Requests]
WHERE
cast(CreatedDate as date) >= COALESCE(#StartDate, CreatedDate)
AND cast(CreatedDate as date) <= COALESCE(#EndDate, #StartDate, CreatedDate)
Logically, if #EndDate is null and #StartDate is not, this effectively becomes:
SELECT *
FROM [dbo].[tbl_Support_Requests]
WHERE
cast(CreatedDate as date) >= #StartDate
AND cast(CreatedDate as date) <= #StartDate
Which will only be true if CreatedDate is equal to #StartDate.
I am slightly concerned by the casts - if they're there because the type of CreatedDate isn't date, I'd strongly suggest that the table definition by updated. If, on the other hand, they're being used to "cast away" a time component, then the same operation should also be being done on the right hand side, inside the COALESCE, so that the values compare equal.
Don't cast your column, it'll be bad for performance. I also assume that your parameters are date data types, but that your column is actually a date and time (such as a datetime2), due to your casting. You can then just use a single ISNULL on the parameters, and then an OR for when they are both NULL:
WHERE (CreateDate >= #StartDate AND CreateDate < DATEADD(DAY,1,ISNULL(#EndDate,#StartDate))
OR (#StartDate IS NULL AND #EndDate IS NULL)
You'll probably want to put an OPTION (RECOMPILE) in there too, as the plan for when they both have NULL could be very different to when they don't.

Get daily data from hourly

I have query which returns hourly data. But I want to get daily data from this query, so all the hourly data per day would be averaged to daily data.
declare #Days int
set #Days = -1
select
dateadd(hour,datepart(hour,Timestamp),cast(CAST((Timestamp) as date) as datetime)) as [Time]
,[value]
from [Employee]
where dateadd(hour,datepart(hour,Timestamp),cast(CAST((Timestamp) as date) as datetime)) >= CONVERT(date, DATEADD(DAY, #Days, GETDATE()))
Assuming you have additional columns you want to average and group by date, you can try something like:
DECLARE #Days int = -1;
SELECT
CAST(Timestamp AS date) AS date
, AVG(Value) AS Value
FROM [Employee]
WHERE Timestamp >= DATEADD(day, #Days, CAST(GETDATE() AS date))
GROUP BY CAST(Timestamp AS date)
ORDER BY date;
Note the refactored WHERE clause that avoids applying a function to the column value. This will allow an index on Timestamp to be used efficiently (sargable expression).

Date parameters returning values outside the range of dates

Using SQL Server Management Studio, I have a query that I'm using date parameters but when I execute the query, I see rows that aren't in the date range selected.
DECLARE #StartDate Date = '7/10/2017'
DECLARE #EndDate Date = '7/17/2017'
SELECT DISTINCT
PROJECTID,
ACTIVITYID, ACTIVITYNAME,
ISPRIMARYRESOURCE, RESOURCEID,
STARTDATE, FINISHDATE,
FORMAT(STARTDATE,'dddd') + ', ' + FORMAT(STARTDATE,'m') + ', ' +
FORMAT(STARTDATE,'yyyy') AS ES_FORMATTED
FROM
Primavera_ODS.TASKRSRCX
WHERE
PROJECTID IN ('ONLINE', 'ESR01', 'H-ONL-Active', 'HNP-NBKRRPLD', 'HNP-RVH-LIV',
'HNP-CSCR-LIV', 'HNP-TCS-LIV', 'HNP-LPT-LIV', 'HNP-DICSP-LIV',
'HNP-NRRVHE', 'HNP-IDS-LIV')
AND FINISHDATE >= #StartDate
AND STARTDATE < #EndDate
ORDER BY
STARTDATE
The STARTDATE and FINISHDATE fields are formatted as datetime.
When the query is executed, the first row is showing a STARTDATE of 2012-11-01 08:00:00.000 and a FINISHDATE of 2018-09-27 17:00:00.000. Clearly not in the date range declared.
What am I doing wrong?
DECLARE #StartDate Date = '7/10/2017'
Is this 7th October 2017 or 10th July 2017?
Either way
FINISHDATE >=#StartDate and STARTDATE < #EndDate
means
'2018-09-27' >= '2017-07-10' AND '2012-11-01' < '2017-07-17'
Both conditions are true
Do you mean this?
STARTDATE < #StartDate AND #EndDate <= FINISHDATE
You need to test both dates lie within the bounds so:
#StartDate BETWEEN STARTDATE AND FINISHDATE
AND
#EndDate BETWEEN STARTDATE AND FINISHDATE
You may also need:
AND
#StartDate < #EndDate
You can also write your dates as '17-July-2017' or '2017-07-17' to avoid any ambiguity.
If your SQL is as per above, then nothing is wrong.
Your criteria is that FINISHDATE >= #StartDate and #StartDate is '7/10/2017'. From the result you get of FINISHDATE = '2018-09-27 17:00:00.000', so clearly FINISHDATE > #startDate.
The criteria also say that STARTDATE < #EndDate. #EndDate is set to '7/17/2017' and you get back STARTDATE = '2012-11-01 08:00:00.000 ', which is true.
My assumption is that your date range should be between #StartDate and #EndDate? If that is correct maybe you could try something like:
AND
FINISHDATE BETWEEN #StartDate AND #EndDate
AND
STARTDATE BETWEEN #StartDate AND #EndDate
Niels
You were exactly right gbn. I've accepted the query parameter and results were returning the data as requested.

Refine SQL date-range query

Attempting to query for when, given parameters #startDate and #endDate, a record occurs in as much of the time frame as is supplied. I have a functional where clause below, but I suspect it can be more direct.
If an end date is supplied, records will not be selected from after that date. If a start date is supplied, records will not be selected from before that date. If no dates are supplied all records will be selected.
SELECT *
FROM myTable
WHERE
(
(#startDate IS NULL AND ((#endDate IS NULL) OR (myTable.[recordDate] <= #endDate)))
OR
(#endDate IS NULL AND ((#startDate IS NULL) OR (myTable.[recordDate] >= #startDate)))
OR
(myTable.[recordDate] BETWEEN #startDate AND #endDate)
)
You could workaround with ISNULL function like below:
SELECT * FROM myTable
WHERE myTable.[recordDate] >= ISNULL(#startDate, '01/01/1900')
AND myTable.[recordDate] <= ISNULL(#endDate, getDate())
This query will select all the rows that are either:
Between #startDate and #endDate inclusive of both
Between #startDate and current date time if #endDate is null
Between 01/01/1900 if #startDate is null and todays' date time if #endDate is null
Between 01/01/1900 if #startDate is null and #endDate
Setup a temp tableceiling with floor and ceiling and join to table on date BETWEEN floor and ceiling. Setup your unbounded conditions(NULL)as 1/1/1900 and 12/31/9999. A colleague showed me this recently and it worked.

SQL Server - Generate date field data in where clause

My query is
Select * from Orders
where ordersdate Between '2013-10-10 00:00:00.00' and '2013-10-10 23:59:59.997'
I need to run this query on daily basis and it should be previous day dates. so how to generate dates in above format is what im struggling with.
Select *
from Orders
where ordersdate >= cast(dateadd(d, -1, getdate()) as date)
and ordersdate < cast(getdate() as date)
Instead of the additonal time you can use >= yesterday's date and < today.
DECLARE #StartDate DATETIME, #EndDate DATETIME
/* set the end date to midnight of the previous day */
SET #EndDate = CONVERT(DATETIME, CONVERT(VARCHAR(10), GETDATE(), 121), 121)
/* set the start date to 1 day previously (thereby getting midnight to midnight) */
SET #StartDate = DATEADD(day, -1, #EndDate)
/* you could use between, but orders placed at midnight might be counted twice (on subsequent day reports) */
Select * from Orders where ordersdate Between #StartDate AND #EndDate
/* or you could use >= and < to guarantee that a order placed at midnight will only be counted once */
Select * from Orders where ordersdate >= #StartDate AND ordersdate < #EndDate
select *
from orders
where datediff(d, ordersdate, getdate()) = 1
/edit/
As per Jason Musgrove comment - such query is easy to write and understand, but depend on rows count may become quite inefficent.
taking a slightly different approach (but probably not as good as Arvo's Answer) and there are quicker ways to perform the cast
select *
from orders
where cast(ordersdate as varchar(11)) = cast( dateadd(dd,-1,getdate()) as varchar(11) )

Resources