I am wanting to limit the user to not be able to search for a time frame longer than a year. So 1/1/2014 to 1/1/2015 is valid, but 1/1/2014 to 3/1/2015 is not valid. They are inputting the dates in a date picker in a SSRS report.
WHERE "view"."myDate" between #firstDate and #secondDate
Is there logic I can put in the WHERE cause that can put these restrictions into affect?
You could add a DATEDIFF check to the WHERE clause to limit the range to a year;
AND DATEDIFF(d, #firstDate, #secondDate) < 366
However, this will return nothing if the range exceeds a year. If you want the query to return upto a years worth of results then you could use something like this;
WHERE "view"."myDate" between #firstDate and
CASE
WHEN DATEDIFF(d, #firstDate, #secondDate) < 366 THEN #secondDate
ELSE DATEADD(d, 365, #firstDate)
END
If you want to raise an error if the user provides an invalid range then you would have to use a stored procedure for your data source and perform parameter validation. Something like this;
CREATE PROC dbo.GetMyData ( #firstDate date, #secondDate ) AS
BEGIN
IF (DATEDIFF(d, #firstDate, #secondDate) > 365)
BEGIN
RAISERROR('Please restrict searches to less than a year.', 16, 1)
RETURN
END
SELECT ...
WHERE "view"."myDate" between #firstDate and #secondDate
END
Related
I have a date in the format of Mar-19 as in March, 2019. I need to select a range for the entire month of March in SQL Server query using only Mar-19 (MMM-yy). The output should be:
start date is >= '03/01/2019' and end date is <= '03/31/2019'. I need to factor in the months of the year with various number of days in the month as well.
Assuming you called your procedure as EXEC dbo.SomeProc #Year, #Month, inside your procedure, you can get your result similar to this:
SELECT *
FROM SomeTable
WHERE DATEPART(YEAR, MyDateColumn) = #Year AND DATEPART(MONTH, MyDateColumn) = #Month
doing something like this:
select *
from INVOICE_HEADING
where INVOICE_DATE >= '06 Dec 2018 00:00:00'
INVOICE_DATE <= '16 Dec 2018 00:00:00'
and I get this message:
"The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart."
How can I write it in a different way (or how can I use datediff here?) to get the result?
The function DATEDIFF returns a signed integer, which can hold values from -2.147.483.648 to 2.147.483.647. If the dates you are applying the function to and the unit you are using (month, day, second, etc.) generate a difference outside these bounds then an error is thrown.
There are a few workarounds:
Use DATEDIFF_BIG if you are using SQL Server 2016+.
Move to a "higher" unit (milliseconds -> seconds -> minutes -> hours and so on) until the value you get can be cast into a integer and make sure that all the values you might apply the function to in the future will still be inside the bounds of an integer. You can then drill down the unit to the one you need by multiplying and handling the value as BIGINT (for example).
It's common for this error to pop up when comparing dates that are not valid to the business or generated by default as 1900-01-01. You can filter these with a WHERE clause, supply a decent default value or convert to NULL. Can also avoid applying the DATEDIFF function with a CASE before it when dates aren't reasonable.
Examples:
DECLARE #OldDate DATE = '1900-01-01'
DECLARE #Now DATE = GETDATE()
SELECT DATEDIFF(SECOND, #OldDate, #Now) AS DateDiffResult
--Msg 535, Level 16, State 0, Line 5
--The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart.
Change the unit from second to minute:
DECLARE #OldDate DATE = '1900-01-01'
DECLARE #Now DATE = GETDATE()
SELECT DATEDIFF(MINUTE, #OldDate, #Now) AS DateDiffResult
-- DateDiffResult: 62599680
Revert the minute to second with a "bigger" data type:
DECLARE #OldDate DATE = '1900-01-01'
DECLARE #Now DATE = GETDATE()
SELECT
CONVERT(BIGINT, DATEDIFF(MINUTE, #OldDate, #Now)) * 60 AS DateDiffResult
-- DateDiffResult: 3755980800
I need to get the number of elapsed days between any two dates with respect to the current date. IE:
mm/dd/yyyy
Current day = 07/10/2015
07/08/2013 ... 07/11/2013 - 4 days elapsed
Current day = 07/10/2015
07/08/2015 ... 07/11/2015 - 2 days have elapsed
I've tried several combinations using DATEDIFF with day as the date part, however, I can't seem to get a clean way to get the days elapsed when the date could be past or present.
EDIT
I know the start date and the end date of a certain business process. They could be this year, last year, two years ago and so on. I need a way via SQL Server functions to figure out the days total elapsed. If it's not the current year, obviously the entire span/range would have elapsed. If it's the current year, perhaps the entire span/range hasn't elapsed and it needs to say how many days are "into the process" based on the respected start time, end time and current time.
Hopefully this makes more sense?
Please help.
I used #Sean Lange, with a small tweak:
DATEDIFF(DAY, #StartDate, case when #EndDate < GETDATE() then #EndDate + 1 else GETDATE() end)
Thanks all.
This is pretty similar to the answer provided by Stan but here is my take on this.
with Something as
(
select CAST('2013-07-08' as datetime) as StartDate
, CAST('2013-07-11' as datetime) as EndDate
union all
select '2015-07-08', '2015-07-11'
)
select *
, DATEDIFF(DAY, StartDate, case when EndDate < GETDATE() then EndDate else GETDATE() end)
from Something
How about this:
Given:
CREATE TABLE dbo.test ( ChildID INT Identity,
Start DateTime
, Finish DateTime
)
and your test data:
insert into dbo.test (start,finish) values('07/08/2013','07/11/2013')
insert into dbo.test (start,finish) values('07/08/2015','07/11/2015')
then
select start,finish
, DATEDIFF(DAY, start, CASE WHEN GETDATE() BETWEEN start and finish
THEN GETDATE() - 1 ELSE finish END) + 1 as elapsed
from dbo.test
gives the result from your example.
You might have to tweak if there are other adjustments for how the current date fits between the range.
I have a table in SQL Server which has many rows, with a created_date column. This column has rows starting from the year 2006.
I want to get all the rows which were created in and before February, 2015. This stored procedure has a parameter #month. It should select all the rows based on the #month value entered.
Here is my query:
select *
from products
where 1=1
and year(created_date) <= 2015
and month(created_date) <= #month
But this query returns only the records which were created in and before February month of previous years excluding records which were created in other months of 2014 (e.g., 2014-03-17, 2014-05-05 are excluded).
I have to get a new date based on the #month entered. Suppose I entered month July, I want to have condition "where created_date < 2015-07-31". So I can do something like this,
So I have changed my query,
declare #date datetime
set #date = CAST((2015 + '-' + #month + '-' + 28) as datetime)
select *
from products
where 1=1
and year(created_date) <= 2015
But this query returns 1905-08-08 00:00:00.000 and I want to get 2015-02-28 00:00:00.000 and also I have to find total number of days based on the #month entered so that I can pass that number to CAST((2015 + '-' + #month + '-' + 28) as datetime) instead of 28.
Just use a single date and specify that the created_date column must be less than that date:
declare #newestDate datetime = '2015-03-01'
select *
from products
where created_date < #newestDate
Note that I set the date to be the 1st March but in the query I use < rather than <=. This will cope with a created_date value including a time component, e.g. 2015-02-28 23:59:59
To generate the value of "February of previous year", you may actually be wanting to use the current month of last year, if so, your date would be:
declare #newestDate datetime =
DATEADD(year, -1, DATEADD(month, DATEDIFF(month, 0, GETDATE())+1, 0))
This would then work next month (i.e. March) and would give your query a rolling month.
Always compare date/time fields to a single value where possible -- this is best for performance as well. You can "round" dates with DATEADD and DATEDIFF.
DECLARE #startOfNextMonth DATETIME;
SELECT #startOfNextMonth = DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) + 1, 0);
select * from products where 1=1 and created_date < #startOfNextMonth;
String manipulation to convert dates is also possible, but tends to perform worse and is tricky to get right. This technique applies in general if you want to "round" to years, minutes, 15-second periods, etcetera, which is much harder with strings.
If you can, rewrite your stored procedure to not take a #month parameter but an absolute value that your clients calculate -- it's more general and tends to be easier to work with. Your query then simply reduces to
select * from products where 1=1 and created_date < #limit;
Of course, if you must use a #month, you can construct this offset in the stored procedure itself:
DECLARE #limit DATETIME =
DATEFROMPARTS(DATEPART(YEAR, GETDATE()), #month, 1)
;
This takes advantage of DATEFROMPARTS, which was introduced with SQL Server 2012. For previous versions, reliably constructing a date is considerably messier. There are many wrong ways to do it that will break if the regional settings are set to something unexpected. DATEADD is again of assistance:
DECLARE #limit DATETIME =
DATEADD(MONTH, (DATEPART(YEAR, GETDATE()) - 1900) * 12 + #month - 1, 0)
;
These are not the only methods to construct datetime values, but string manipulation is in any case tricky (because the only reliable format that will not break under regional settings is YYYYMMDD, no dashes).
In this question: Create a date with T-SQL you will see how to construct an sql-server date data type given a certain year and month. Suppose you call that 'my_date'.
You will then be able to do the following:
SELECT * FROM products WHERE created_date < my_date
I have a table that has a TASK_START_DATE and TASK_FINISH_DATE Columns of type datetime
I need help with a query that returns all Tasks when the Task: (date = just the date - I think I can do a conversion to the date from datetime on SQL 2008R2, it works fine)
- is within 2 weeks previous of the current date or two weeks after the current date.
Similarly I also need the records whose TaskEnd values are within 2 weeks previous or two weeks before
I've been trying things like which would get tasks where the start date is within the two previous weeks, but I have to do the same for TASK_FINISH_DATE and I think my and's and or's are all jumbled up, any help is appreciated.
Convert(Date, TASK_START_DATE) <= Convert(Date, DateAdd(ww, -2, GetDate()))
Short version:
How do I correctly write a query that combines all records with the TASK_START_DATE OR TASK_END_DATE within two weeks in the future or past, i.e.
Select Task_ID, TASK_NAME, TASK_START_DATE, TASK_END_DATE
where
???
You can add days to your date for comparision:
Select * from Table
Where column between getdate()-14 and getdate()+14
You don't need to use "Convert" function. "GetDate" function returns datetime value and your columns' types are datetime. You can add day number directly like this:
Select * from Table
Where (TASK_START_DATE between getdate() - 14 and getdate() + 14)
or (TASK_FINISH_DATE between getdate() - 14 and getdate() + 14)
You can declare variables or have the comparison dates right in the where clause. I use GETDATE() to get the date/time for right now as it returns a DATETIME object. Then I use DATEADD to adjust it for days, months, years, etc, and then you have to convert it to a DATE before sticking it in a variable of type DATE. Note in the DATEADD method I pass in the adjustment type (D = days), then adjust it + or - 14 days.
Alternatively you could just use 14 days ago to the minute if you don't do the DATE conversions...you'd have to remove the converts from the variable declarations as well as the where clause. Depends on the results you want though.
DECLARE #twoWeeksAgo DATE = CONVERT(DATE, DATEADD(D, -14, GETDATE()));
DECLARE #twoWeeksAhead DATE = CONVERT(DATE, DATEADD(D, 14, GETDATE()));
SELECT
Task_ID,
TASK_NAME,
TASK_START_DATE,
TASK_END_DATE
FROM
TABLE
WHERE
CONVERT(DATE, TASK_START_DATE) BETWEEN #twoWeeksAgo AND #twoWeeksAhead
OR CONVERT(DATE, TASK_END_DATE) BETWEEN #twoWeeksAgo AND #twoWeeksAhead
Also note that the BETWEEN operator in the WHERE clause is inclusive, meaning it will include records where the TASK_START_DATE is equal to the dates held by the variables. If you wanted to exclude records with the same value as #twoWeeksAhead, for example, you would have to use something like
WHERE
(CONVERT(DATE, TASK_START_DATE) >= #twoWeeksAgo
AND CONVERT(DATE, TASK_START_DATE) < #twoWeeksAhead)
OR (CONVERT(DATE, TASK_END_DATE) >= #twoWeeksAgo
AND CONVERT(DATE, TASK_END_DATE) < #twoWeeksAhead)