Select rows with date range within another date range - sql

I have a table of accounts that has columns for start date and end date. I want the user to supply a start date and end date and all data must be returned where the account was active at any time between the user specified start date and end date.
The catch is that the end date may be null if the account is still currently active.
The account must be selected if it was open at any time between the user specified range which means that even accounts that were opened or closed between the range must be included.
Here is a picture of what I want.
The yellow part is the date range entered by the user. The green parts is what I want selected. The light red part is what I don't want selected. The arrows on the end of G, H and I mean that those accounts don't have an end date. All other ones that don't have an arrow have an end date.

So, this amounts to checking that the account start date is prior to the user supplied end date and the account end date is after the user supplied start date (or is null, in which case we don't even need to check it):
where
account.start_date < #user_end_date and
(account.end_date >= #user_start_date or account.end_date is null)

SELECT
*
FROM
accounts
WHERE
(start_date >= :user_supplied_start AND start_date <= :user_supplied_end)
OR
(end_date >= :user_supplied_end AND end_date <= :user_supplied_start)
OR
(start_date <= :user_supplied_start AND end_date IS NULL)

SELECT *
FROM accounts
WHERE start_date <= #input_end_date
AND (end_date >= #input_start_date OR (end_date IS NULL AND NOW() >= #input_start_date))

Related

Hardcoded date required instead of automated date minus 1

case when "DocDate"<=CAST(ADD_DAYS(CURRENT_DATE,-1) as date) then sum("TransValue") else 0
I need a hardcoded date instead of (CURRENT_DATE) so that my user can able to fetch the report on all days with actual result for that particular date.
Thanks
Kumar

SQL - Select query not displaying all dates

I have a table that has a start date, an end date, and the pay period information according to the start and end dates. When I try to find the pay period information with a date range, the very first pay period information does not show in the result.
For example, when I run the following query:
select *
FROM PayPeriod
where start_date between '2020-12-01' and '2020-12-21'
I should see the following result:
Start_date End_date Pay_perild
2020-11-22 2020-12-05 2020-12-wk1
2020-12-06 2020-12-19 2020-12-wk3
2020-12-20 2021-01-02 2021-01-wk1
Instead, I get:
Start_date End_date Pay_period
2020-12-06 2020-12-19 2020-12-wk3
2020-12-20 2021-01-02 2021-01-wk1
The date range and the pay period that includes '2020-12-01' is omitted. Why isn't it showing, and how do I correct this?
Looks like I've got what you wanted. You need to intersect two time intervals.
To find intersecting intervals of two tables (say TableA and TableB, I use tables as more general case to distinguish two intervals by their meaning/role/whatever) you need to compare begin date of one table with end date of another for both tables (putting each of them to "one" and "another" role):
TableA.start_date < TableB.end_date
and TableB.start_date < TableA.end_date
It is the rule for the case where your intervals are continuous, e.g. end_date of one period is "just before" (like real numbers) of the start_dare of another (so all items in the interval will have start_date <= item_date < end_date). For discrete intervals (like days, where duration of one day will have identical values of start_date and end_date) there would be <= in intersection condition.
So, your query will look like
DECLARE #period_from date = CONVERT ('2020-12-01' 23),
#period_to date = CONVERT ('2020-12-21', 23);
select *
FROM PayPeriod
where start_date < #period_to /*or <= depending on inclusion of end_date*/
and #period_from < end_date /*or <= depending on inclusion of end_date*/
The query is returning the result as you instructed. It's working perfectly. In your query you put the date range condition one the start_date:
where start_date between '2020-12-01' and '2020-12-21'
The first row that you expect has start_date = 2020-11-22. This date is not in the rage you specified in the condition.
If you want the first row in the result set simply you need to change the condition.
If you have to put condition on the start date you have to make the date range wider in the condition. For example:
SELECT *
FROM PayPeriod
WHERE start_date between '2020-11-21' and '2020-12-21'
Based on your application requirement you have to arrange the condition.

trying to selecting rows that are between two date for a period of time

This problem is like a brain teaser....so i have two dates, start date and end date and i want to select all the rows that are active between those two dates and if the period between those dates have passed then the rows should not be selected. Please note that these dates includes time
Here is an example before the code Start date = '15-MAY-2020 08:00
AM' and End date = '16-MAY-2020 08:00 AM'
As you can see there is 24 hour period between those dates and i want
to select ALL ROWS THAT ARE BETWEEN THE START DATE AND END DATE and if
the the time becomes '16-MAY-2020 08:01 AM' then those rows should not
be displayed anymore.
Now the code
select id, title, color, start_date, end_date
from colors
where end_date >= start_date and end_date <= sysdate
Summary:
If a color is between a certain start and end then it must only be displayed during that start and end otherwise it should not be shown
It is like eating ice cream, you get the ice cream and start to eat it (start) and you eat it until its is finished (end) then you have no more ice cream
Same with the colors, it starts to show at a particular date and time and has a particular date and time when it ends after that the color does not show anymore
You are close. Both your conditions needs to reference sysdate:
select id, title, color, start_date, end_date
from colors
where start_date <= sysdate and end_date >= sysdate

how to compare date parts in SQL Oracle

I have a bit tricky question. E.g. I have a start_date: 15/01/2015 and an end date: 17/03/2015 for given record and I would like to generalize that to know, if the record with those exact start and end date belongs to January (by my definition even if it is 31/01/2015, then it belongs to January).
I did the following:
sum(case when to_date('2015/01/01','yyyy/mm/dd') between ROUND(dtime_method_start,'MONTH') and ROUND(dtime_method_end,'MONTH') then 1 else 0 end) as flag_jan
But the problem with Round function is, that it takes everything from 16-31 as next month, which is no good for me. How can I fix it or rewrite it to make it comply with my definition?
I want to know if a record with certain dtime_method_start and dtime_method_end belongs to January. I have many records with many different start and end dates and want to know how many of them belong to January.
SELECT expected,
CASE
WHEN to_date('01/01/2015','DD/MM/YYYY') = ALL (trunc(start_date,'MONTH'), trunc(end_date,'MONTH'))
THEN 1
ELSE 0
END flag_jan
FROM
(SELECT 'notmatch 0' expected
, to_date('15/01/2015','DD/MM/YYYY') start_date
, to_date('17/03/2015','DD/MM/YYYY') end_date
FROM dual
UNION ALL
SELECT 'match 1'
, to_date('12/01/2015','DD/MM/YYYY')
, to_date('23/01/2015','DD/MM/YYYY')
FROM dual
) dates;
this query compares the truncated start_date and end_date to match the first day of the month.
To check another month_flag, juste change the date in the first case expression.
Just use trunc instead of round. Trunc with parameter 'MONTH' will truncate the date to the first day of month. If you test with between using first day of month it's ok.
I would compare the stored dates directly to a range based on the input date, rather than applying a function to every date:
count(case when dtime_method_start >= trunc(to_date('2015/01/01','yyyy/mm/dd'),'mm')
and dtime_method_start < add_months(trunc(to_date('2015/01/01','yyyy/mm/dd'),'mm'),1)
then 1
end) as flag_jan
Or you could
count(case when trunc(dtime_method_start,'mm') = trunc(to_date('2015/01/01','yyyy/mm/dd'),'mm')
then 1
end) as flag_jan

Find and count consecutive records in ruby on rails

I have an app that tracks employee times. Employees are required to have at least 2 days off every 12 days... An employee should enter a record with boolean true for day_off...but, in case they don't I also want to find breaks in days that could also days off. I am trying to simply count records whos date decrements by one day, starting from the boolean day_off Or break in consecutive dates...and ending on a given date.
This is the helper I am working on
def consecutive_days_on(user, dutylog)
# dutylog will be supplied via a loop
last_day_off = user.dutylogs.where("entry_date < ?", dutylog.entry_date).where(day_off: true).last
start_date = dutylog.entry_date
if last_day_off.present?
end_date = last_day_off.entry_date
# if the user logged their days off
else
end_date = user.dutylogs.where("entry_date < ?", dutylog.entry_date).last.entry_date
# as of now this just finds the last record...it needs to iterate and increment date to find a break in days on
# to find break in consecutive dates...if user did not log days off
end
user.dutylogs.where("entry_date >= ? AND entry_date <= ?", start_date, end_date).count
# count the records between the two dates...to find consecutive days on
end
I refactored my helper...and it works. I decided to rely on the user entering a day as off in their log...and not assuming that a break in entered days could be considered a day off.
def consecutive_days_on(user, dutylog)
last_day_off = user.dutylogs.where(day_off: true).where("entry_date < ?", dutylog.entry_date).select(:entry_date).last
start_date = dutylog.entry_date
if last_day_off.present?
end_date = last_day_off.entry_date
else
end_date = dutylog.entry_date
end
a = user.dutylogs.where("entry_date >= ? AND entry_date <= ?", end_date, start_date).count
a-1
end