Selecting records using between operator SQL Server - sql

I am getting confusing in writing the best stored procedure for my requirement.
I am filtering records based on StartDate and EndDate.
So I want to get records whose StartDate and EndDates are between StartDate & EndDate range.
Previously I had asked this question Here in SE, and got some answers. But later I found that the query is not giving me correct results.
So the answer I found there is:
select *
from tbl
Where (Event_Startdate between #StartDate and #EndDate)
and (Event_Enddate between #StartDate and #EndDate)
Lets say I have records :
If I execute the above query with inputs like:
#StartDate = '1/1/2000',
#EndDate = '5/16/2014',
The query above gives no records at all right.. because here Event_StartDate is between the StartDate and EndDate, where as End Date is not between the range.
But what I want is if the StartDate or EndDate is between range, then it should be selected.
Then immediately OR operator came into my mind, I tried by changing And to OR in my query
select *
from tbl
Where (Event_Startdate between #StartDate and #EndDate)
OR (Event_Enddate between #StartDate and #EndDate)
It gave the correct answer in this situation.
But the problem with this query is it doesn't check the second condition, which is after 'OR' If the first condition is true. Suppose if i gave input as:
#StartDate = '1/1/2000',
#EndDate = '7/25/2014'
It will select all records in the table because StartDate is in between 1/1/2000 to 7/25/2014 which is true, so it does nt check whether EndDate is in between the range or not, it does'nt care about EndDate.
I hope my problem is clear to u..Please somebody help with this...

Try this
select * from (
select * from tbl Where Event_Startdate between #StartDate and #EndDate
) AS A
Where Event_Enddate between #StartDate and #EndDate

This will work for sure
select *
from tbl
Where ( #StartDate between Event_Startdate and Event_Enddate
or Event_Startdate between #StartDate and #EndDate)
and ( #EndDate between Event_Startdate and Event_Enddate
or Event_Enddate between #StartDate and #EndDate)

If you want rows whose ranges are completely within the bounds of the specified range, specify that Event_Startdate should be not earlier than #StartDate and Event_Enddate not later than #EndDate:
WHERE Event_Startdate >= #StartDate
AND Event_Enddate <= #EndDate

If You need to filter all overlaping intervals(inner and outer)and optionaly with NULLs in Event_Startdate and Event_Enddate, try this:
select *
from tbl
Where
1=CASE WHEN Event_Startdate IS NOT NULL AND Event_Enddate IS NOT NULL THEN
CASE WHEN #StartDate<=Event_Startdate AND #EndDate>=Event_Enddate THEN 1
WHEN #StartDate>=Event_Startdate AND #EndDate<=Event_Enddate THEN 1
WHEN #StartDate<=Event_Startdate AND #EndDate BETWEEN Event_Startdate AND Event_Enddate THEN 1
WHEN #EndDate>=Event_Enddate AND #StartDate BETWEEN Event_Startdate AND Event_Enddate THEN 1
ELSE 0 END
WHEN Event_Startdate IS NULL AND Event_Enddate IS NOT NULL AND #StartDate<=Event_Enddate THEN 1
WHEN Event_Enddate IS NULL AND Event_Startdate IS NOT NULL AND #EndDate>=Event_Startdate THEN 1
ELSE 0 END

well you can see in the data:
your date are different.
in the db, it is
'yyyy/mm/dd'
and your variables are
'dd/mm/yyyy'

Related

Sql Server- Get the dates from the database between the range supplied

I have an issue to get the records if the FtableID at any point in the range (Start date and End date) has a StatusID=2.
My table Structure is
ID FTableID StatusID AddedOn
75324 53591 1 2019-03-17 06:48:14.490
75325 53591 2 2019-03-18 06:48:14.663
75326 53591 3 2019-03-19 06:54:20.830
#StartDate Datetime='2019/03/17 23:00:00' ,
#EndDate Datetime='2019/03/20 23:59:59'
Select ID, FTableID,StatusID,AddedOn from MyTableName where FTableID=53591
And StatusID=2 and AddedOn <= #EndDate
I know my query is wrong and it gives the record even when I pass the #startdate after its status gets changed to 3 (Completed)
I am confused to set the start date filter.
I need to check if this FtableID record is in status id =2 at any point in the range supplied
The record should come If I pass the #StartDate Datetime='2019/03/18 23:00:00', #EndDate Datetime='2019/03/20 23:59:59' because it is in this range it was in the status=2
The record should not come If I pass the #StartDate Datetime='2019/03/19 23:00:00', #EndDate Datetime='2019/03/20 23:59:59' because it was convertted to statusID=3
Please suggest me on this. Thanks in advance.
use this
select *
from YourTableName
where AddedOn between (#StartDate and #EndDate)
and StatusID=2
One method uses exists.
I would simplify your date arithmetic as well, so:
declare #StartDate datetime '2019-03-17 23:00:00';
declare #EndDate datetime = '2019-03-20'
select t.*
from mytablename t
where exists (select 1
from mytablename t2
where t2.ftableid = t.ftableid and
t2.statusid = 2 and
t2.AddedOn >= #StartDate and
t2.AddedOn < #EndDate
);

BETWEEN #Start and #End Date; Not pulling in records which fall beyond the date

Currently working on a t-sql query which is supposed to get a list of all records that fall between the current fiscal year (we use 4-4-5 calendar).
The record's start and end date are 06/02/2018, 31/07/2020.
The date I am filtering for is:
DECLARE #StartDate DATE = '12-29-2018';
DECLARE #EndDate DATE = '12-31-2019';
The condition I have in my where clause is:
AND
(
(o.Revenue_Start_Date__c >= #StartDate AND o.Revenue_End_Date__c <= #EndDate) OR (o.Revenue_End_Date__c >= #StartDate AND o.Revenue_End_Date__c <= #EndDate)
)
I have tried variations of BETWEEN as well. Any idea what I may be doing wrong and how do I get a list of all records to be included if it falls within the coresponding dates.
ANSWER:
AND ( -- Starts Within range
( o.Revenue_Start_Date__c
BETWEEN #StartDate
AND #EndDate
)
OR -- Ends within range
(
o.Revenue_End_Date__c
BETWEEN #StartDate
AND #EndDate
)
OR -- SPANS Range
(
o.Revenue_Start_Date__c < #StartDate
AND
o.Revenue_End_Date__c > #EndDate
)
)
This seems to be working for me just now.
For fall through cases, this should work.
o.Revenue_Start_Date__c <= #EndDate AND o.Revenue_End_Date__c >= #StartDate
Is this what you want?
(o.Revenue_Start_Date__c < #EndDate AND
o.Revenue_End_Date__c >= #StartDate
)
This is the logic for overlapping intervals. Note that the inequalities might be exact or inexact depending on your actual definitions of overlapping.

Recursive CTE Returns Value Outside of Range

While searching for a method to create date ranges I came across a problem with the following query:
DECLARE #StartDate DateTime = '2000-01-01 01:00';
DECLARE #EndDate DateTime = '2020-01-01 00:00';
with Dates as (
select
#StartDate fromDate
UNION ALL
(Select
fromDate = dateadd(day, 1, #EndDate)
from
Dates
where
fromDate >= #StartDate AND
fromDate < #EndDate ))
Select * from Dates
OPTION (MAXRECURSION 0);
The following query returns two rows, one of which is outside of the range,
fromDate
-----------------------
2000-01-01 01:00:00.000
2020-01-02 00:00:00.000
I am aware that there is a way to fix this issue by changing the second half of the query to be different, for example:
Select * from Dates Where fromDate <= #EndDate
I have the following questions:
what is wrong with the query as is?
Why is it that this query returns two values, one of which lies outside the range provided?
This is using Microsoft SQL Server 2008 R2
Because your Recursive CTE add one day from fromDate
Select
fromDate = dateadd(day, 1, #EndDate)
but your condition filter fromDate
where
fromDate >= #StartDate AND
fromDate < #EndDate ))
If you want to do make calendar table by Recursive CTE.
you can try this.
with Dates as (
select #StartDate fromDate,#EndDate endDate
UNION ALL
Select
fromDate = dateadd(day, 1, fromDate),endDate
from
Dates
where
dateadd(day, 1, fromDate) <= #EndDate
)
Select * from Dates
OPTION (MAXRECURSION 0);
The simple answer for #1 / #2: You are selecting DATEADD(day, 1, #endDate) -- which, by definition, is 1 day 'over' your date range.
The real answer: To get the result you want, change:
(Select
fromDate = dateadd(day, 1, #EndDate)
To:
(Select
fromDate = dateadd(day, 1, fromDate)

greater than and less than equals to in sql?

how can i use greater than equal to and less than equal to instead of using between in SQL
I'm checking for date variable in sql
i tried like this.
Date between coalesce(#fromDate,Date) and coalesce(#toDate,Date)
but if user does not enter any of date (fromDate or toDate)
so that I need to convert above condition in greater than equal to and less than equal to
please help in syntax in sql.
thanks
IF #fromDate IS NULL
BEGIN
SET #fromDate = '1900-01-01';
END;
IF #toDate IS NULL
BEGIN
SET #toDate = '2099-01-01';
END;
SELECT things
FROM table
WHERE date_field BETWEEN #toDate AND #fromDate;
This code will essentially give you an arbitrarily large range to check which should give you reasonable performance and return all results (assuming that's what you want when neither value is supplied).
This code can be shortened to:
SELECT things
FROM table
WHERE date_field BETWEEN Coalesce(#toDate, '1900-01-01') AND Coalesce(#fromDate, '2099-01-01');
But I kept the verbose version to illustrate.
Try this
SELECT Date FROM TableName WHERE Date > #fromDate AND Date < #toDate
SELECT *
FROM dbo.Account AS a
WHERE 1 = 1
AND (
#toDate IS NULL
OR a.CreateDate <= #toDate
)
AND (
#fromDate IS NULL
OR a.CreateDate >= #fromDate
)
Please note the 1 = 1 is only there to make the conditions clear and is by no means needed.
This should be what the where clause would look like.
Where
Date >= #fromDate
And
Date <= #toDate

What is a good way to find gaps in a set of datespans?

What is a way to find gaps in a set of date spans?
For example, I have these date spans:
1/ 1/11 - 1/10/11
1/13/11 - 1/15/11
1/20/11 - 1/30/11
Then I have a start and end date of 1/7/11 and 1/14/11.
I want to be able to tell that between 1/10/11 and 1/13/11 there is a gap so the start and end date is not possible. Or I want to return only the datespans up to the first gap encountered.
If this can be done in SQL server that would be good.
I was thinking to go through each date to find out if it lands in a datespan... if it does not then there's a gap on that day.
Jump to 2nd last code block for: *I want to be able to tell that
between 1/10/11 and 1/13/11 there is
a gap so the start and end date is*
not possible.
Jump to last code block for: *I want to return only
the datespans up to the first gap
encountered.*
First of all, here's a virtual table to discuss
create table spans (date1 datetime, date2 datetime);
insert into spans select '20110101', '20110110';
insert into spans select '20110113', '20110115';
insert into spans select '20110120', '20110130';
This is a query that will list, individually, all the dates in the calendar
declare #startdate datetime, #enddate datetime
select #startdate = '20110107', #enddate = '20110114'
select distinct a.date1+v.number
from spans A
inner join master..spt_values v
on v.type='P' and v.number between 0 and datediff(d, a.date1, a.date2)
-- we don't care about spans that don't intersect with our range
where A.date1 <= #enddate
and #startdate <= A.date2
Armed with this query, we can now test to see if there are any gaps, by
counting the days in the calendar against the expected number of days
declare #startdate datetime, #enddate datetime
select #startdate = '20110107', #enddate = '20110114'
select case when count(distinct a.date1+v.number)
= datediff(d,#startdate, #enddate) + 1
then 'No gaps' else 'Gap' end
from spans A
inner join master..spt_values v
on v.type='P' and v.number between 0 and datediff(d, a.date1, a.date2)
-- we don't care about spans that don't intersect with our range
where A.date1 <= #enddate
and #startdate <= A.date2
-- count only those dates within our range
and a.date1 + v.number between #startdate and #enddate
Another way to do this is to just build the calendar from #start
to #end up front and look to see if there is a span with this date
declare #startdate datetime, #enddate datetime
select #startdate = '20110107', #enddate = '20110114'
-- startdate+v.number is a day on the calendar
select #startdate + v.number
from master..spt_values v
where v.type='P' and v.number between 0
and datediff(d, #startdate, #enddate)
-- run the part above this line alone to see the calendar
-- the condition checks for dates that are not in any span (gap)
and not exists (
select *
from spans
where #startdate + v.number between date1 and date2)
The query returns ALL dates that are gaps in the date range #start - #end
A TOP 1 can be added to just see if there are gaps
To return all records that are before the gap, use the query as a
derived table in a larger query
declare #startdate datetime, #enddate datetime
select #startdate = '20110107', #enddate = '20110114'
select *
from spans
where date1 <= #enddate and #startdate <= date2 -- overlaps
and date2 < ( -- before the gap
select top 1 #startdate + v.number
from master..spt_values v
where v.type='P' and v.number between 0
and datediff(d, #startdate, #enddate)
and not exists (
select *
from spans
where #startdate + v.number between date1 and date2)
order by 1 ASC
)
Assuming MySQL, something like this would work:
select #olddate := null;
select start_date, end_date, datediff(end_date, #olddate) as diff, #olddate:=enddate
from table
order by start_date asc, end_date asc
having diff > 1;
Basically: cache the previous row's end_date in the #olddate variable, and then do a diff on that "old" value with the currel enddate. THe having clause will return only the records where the difference between two rows is greater than a day.
disclaimer: Haven't tested this, but the basic query construct should work.
I want to be able to tell that between
1/10/11 and 1/13/11 there is a gap so
the start and end date is not
possible.
I think you're asking this question: does the data in your table have a gap between the start date and the end date?
I created a one-column table, date_span, and inserted your date spans into it.
You can identify a gap by counting the number of days between start date and end date, and comparing that the the number of rows in date_span for the same range.
select
date '2011-01-14' - date '2011-01-07' + 1 as elapsed_days,
count(*) from date_span
where cal_date between '2011-01-07' and '2011-01-14';
returns
elapsed_days count
-- --
8 6
Since they're not equal, there's a gap in the table "date_span" between 2011-01-07 and 2011-01-14. I'll stop there for now, because I'm really not certain what you're trying to do.