WHERE 5 business days - sql

I'm trying to get the next 5 business days, using sysdate in the WHERE (ie.
where trunc(teststart) between trunc(sysdate) and trunc(sysdate+4)),
but if the range includes Friday, it needs to count weekend days, Saturday & Sunday.
What is the command that will tell you the day of the week when looking at the sysdate or sysdate+3 (or any number)? How would you accomplish something like this?

You can't do this calculation because there is no way that oracle know what exactly is a business day. This is because every region has your own hollidays. To do this you will have to create a table calendar and put all days on it marking which ones is business day. Then you can just join your table with this calendar table using a between clause

#JorgeCampos point is well taken about day 1. You indicate with MON 0 that Monday is the start of the week, NLS settings on the DB and your locale determine this.
select to_char(sysdate, 'D'), to_char(sysdate,'DAY') from dual;
gives the result you asked for. We have a table that gets the next year populated in December for the next year. Includes all holidays, etc.
JCAL_JOB_DATE NOT NULL DATE
JCAL_USER_ID VARCHAR2(30)
JCAL_ACTIVITY_DATE DATE
JCAL_BUSINESS_DAY VARCHAR2(2)
JCAL_HOLIDAY VARCHAR2(2)
JCAL_WEEKEND VARCHAR2(2)
This is used to forecast jobs in the future, and some recurring jobs that do not want to run on holidays or weekends for example.
select jcal_job_date from jcal where
JCAL_JOB_DATE > sysdate
and JCAL_BUSINESS_DAY='Y'
and rownum <6;
This is one not-so-good way to get the fifth business day. Fetch You can use a lot of other functions to streamline this.
This kind of table is VERY useful to determine the same information (work, holiday, weekend) in the past.
Where I am we have holidays that fall on the last Thursday of November and extra holidays are added in there. Programming for that is hard when compared to a simple lookup that works great.

Related

how to automate the date change in a query using transact sql

I work for a company where everyday I modify a query by changing the date of the day before, because the report is always from the previous day.
I want to automate the date change. I have made a table with two columns, one with all dates from this year and another with bits where if 0 is a working day and 1 if is a holiday.
I have successfully automated a little bit by telling if the day before is a working day then subtract 1 from the date (This is what happens everyday). But the problem is, that if is Monday appears as Friday, because Saturday and Sunday are not billable. And let's also say, that if today is Thursday and Wednesday and Tuesday we're holidays, then the report will run on Monday. I will leave you a picture, that shows how the table is made with dates.
Remembering, that if there is no holidays in the middle of the week, always will be subtract one.
The way to do this sort of thing is close to what you have done, but just extend it further. Create a BusinessDate table that has every date, and then every rule you have implemented inside it. You can go so far as to include a column such as ReportDate which will return,for every date, what date the report should be run for.
Do this once, and it will work forever more. You may have to update for future holidays once a year, but better than once a day!
It will also allow you to update things specific for your business, like quarter dates, company holidays, etc.
If you want to know more on the subject, look up topics around creating a date dimension in a data warehouse. Its the same general issue you are facing.
Too complicated for a comment and it involves a lot of guessing.
So everyday, your process starts by first determining if "today" is a work day. So you would do something like:
if exists (select * from <calendar> where date = cast (getdate() as date) and IsWorkday = 1")
begin
<do stuff>
end;
The "do stuff" section would then run a report or your query (or something that isn't very clear) using the most recent work day prior to the current date. You find that date using something like:
declare #targetdate date;
set #targetdate = (select max(date) from <calendar>
where date < cast (getdate() as date)
and IsWorkday = 1);
if #targetdate is not null
<run your query using #targetdate>
That can be condensed into less code but it is easier to understand when the logic is written step-by-step.

Oracle Week Number from a Date

I am brand new to Oracle. I have figured out most of what I need but one field is driving me absolutely crazy. Seems like it should be simple but I think my brain is fried and I just can't get my head around it. I am trying to produce a Sales report. I am doing all kinds of crazy things based on the Invoice Date. The last thing I need to do is to be able to create a Week Number so I can report on weekly sales year vs year. For purposes of this report my fiscal year starts exactly on December 1 (regardless of day of week it falls on) every year. For example, Dec 1-7 will be week 1, etc. I can get the week number using various functions but all of them are based on either calendar year or ISO weeks. How can I easily generate a field that will give me the number of the week since December 1? Thanks so much for your help.
Forget about the default week number formats as that won't work for this specific requirement. I'd probably subtract the previous 1 December from invoice date and divide that by 7. Round down, add 1 and you should be fine.
select floor(
(
trunc(invoiceDate) -
case
-- if December is current month, than use 1st of this month
when to_char(invoiceDate, 'MM') = '12' then trunc(invoiceDate, 'MM')
-- else, use 1st December of previous year
else add_months(trunc(invoiceDate, 'YYYY'), -1)
end
) / 7
) + 1
from dual;

create a view to have relative dates

I have a query which returns data between two dates. Typically those dates are Monday the previous week & Friday the previous week. I've been asked to make this query a view. I have instead made it a stored procedure where the user can enter the two dates. However I would like to know if it would be possible to create a view purely out of my own interest.
Eg. Today is Thursday 21st April. So the from date would be Monday 11th April and the to date would be Friday 15th April.
Is there anyway to setup my query so no matter what day it is this week it will select Monday & Fridays date? Then obviously next week it would automatically select the from date as 18th & the to date as 22nd?
To find Monday and Friday of last week (this is not sensitive to DATEFIRST):
CAST(DATEADD(WEEK,DATEDIFF(WEEK,0,GETDATE())-1,0) AS DATE) 'Monday Last Week'
CAST(DATEADD(WEEK,DATEDIFF(WEEK,0,GETDATE())-1,4) AS DATE) 'Friday Last Week'
This works because Date = 0 was a Monday:
SELECT DATENAME(WEEKDAY, 0) 'What Was Day Zero'
What Was Day Zero
------------------------------
Monday
So your view would be something like (untested):
CREATE VIEW SomeView AS
SELECT
SomeCols
FROM
SomeTable S
WHERE S.SomeDate BETWEEN
CAST(DATEADD(WEEK,DATEDIFF(WEEK,0,GETDATE())-1,0) AS DATE)
AND
CAST(DATEADD(WEEK,DATEDIFF(WEEK,0,GETDATE())-1,4) AS DATE);
I liked #Les H's solution. Thinking this might be needed for a column whose type is not date, but something like datetime, datetime2 I think something like this might be better:
CREATE VIEW SomeView AS
SELECT
SomeCols
FROM
SomeTable S
WHERE
S.SomeDate >= DATEADD(WEEK,DATEDIFF(WEEK,0+(7*1),GETDATE()),0)
AND
S.SomeDate < DATEADD(WEEK,DATEDIFF(WEEK,0+(7*1),GETDATE()),5)
Here I propose a defensive coding against selecting date\time values with a range (between wouldn't work) and I just slightly changed the expression to make it a little more obvious what we are doing and one could simply change the *1 part to mean N weeks before (less tricky I guess).

SQL Query to Count Number of Days, Excluding Holidays/Weekends

I have a "workDate" field and a "receivedDate" field in table "tblExceptions." I need to count the number of days beteen the two. workDate always comes first - so, in effect, it's kind of like workDate is "begin date" and receivedDate is "end date". Some exclusions make it tricky to me though:
First, I need to exclude holidays. i do have a table called "tblHolidays", with one field - holidayDate. I have holidays stored up through next year, so maybe I can incorporate that into the query?
Also, most flummoxing is that work dates can never occur on weekends, but received dates can. So, i somehow need to exclude weekends when i'm counting, but allow for a weekend if the received date happens to fall on a saturday or sunday. so, if the work date is June 3rd, 2011, and received date is June 11th, 2011, the count of valid days would be 7, not 9.
Any help on this is much appreciated. Thanks!
Something like this should give you the number of days with the holidays subtracted:
select
days = datediff(day, workDate, receivedDate)
- (select count(*) from tblHolidays where holidayDate >= workDate and holidayDate < receivedDate)
from
tblExceptions
Note that the date functions differ between database systems. This is based on MS SQL Server, so it may need adapting if you are using some other database.
If you have a table full of dates to include (non-weekends, non-holidays, etc.) and you knew when the 'begin' date and the 'end' date is, then you can do something roughly like this:
select count(*) from tblIncludedDates where beginDateValue <= dateField and endDateValue >= dateField
to get the number of valid days between those dates.

SQL query to search by day/month/year/day&month/day&year etc

I have a PostgreSQL database with events. Each event has a datetime or an interval. Common data are stored in the events table and dates are stored in either events_dates (datetime field) or events_intervals (starts_date, ends_date both are date fields).
Sample datetime events
I was born on 1930-06-09
I got my driver's license on 1950-07-12
Christmas is on 1900-12-24 (1900 is reserved for yearly reoccuring events)
Sample interval events
I'll be on vacation from 2011-06-09 till 2011-07-23
Now I have a user that will want to look up these events. They will be able to fill out a form with from and to fields and in those fields they can enter full date, day, month, year, day and month, day and year, month and year in one or both fields.
Sample queries
From May 3 to 2012 December 21 will look for events between May 3 and December 21 whose max year is 2012
From day 3 to day 15 will look for events between the 3rd and 15th day of every month and year
From day 3 will look for events on the 3rd day of every month and year (same if from is empty and to is not)
From May 3 to June will look for events between May 3 and last day of June of every year
etc.
Any tips on how to write a maintanable query (it doesn't necessarily have to be fast)?
Some things that we thought of
write all possible from, to and day/month/year combinations - not maintable
compare dates as strings e.g. input: ____-06-__ where _ is a wildcard - I wouldn't have to generate all possible combinations but this doesn't work for intervals
You can write maintainable queries that additionally are fast by using the pg/temporal extension:
https://github.com/jeff-davis/PostgreSQL-Temporal
create index on events using gist(period(start_date, end_date));
select *
from events
where period(start_date, end_date) #> :date;
select *
from events
where period(start_date, end_date) && period(:start, :end);
You can even use it to disallow overlaps as a table constraint:
alter table events
add constraint overlap_excl
exclude using gist(period(start_date, end_date) WITH &&);
write all possible from, to and day/month/year combinations - not maintable
It's actually more maintainable than you might think, e.g.:
select *
from events
join generate_series(:start_date, :end_date, :interval) as datetime
on start_date <= datetime and datetime < end_date;
But it's much better to use the above-mentioned period type.