create a view to have relative dates - sql

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).

Related

How can I get the same week day from previous year in Tableau using a calculated field? For example the week day of 06/02/2020

I need to add the week day from previous year on the 3rd column.
Form example 06/02/2021 was on a Wednesday. I need the week day of 06/02/2021.
Thanks
try this:
SELECT DATENAME(weekday,DATEADD(YEAR, -1, '06-02-2021'))
Tableau is notoriously difficult to figure out work days. As some have suggested, it may be easier to use the underlying database to calculate this. However, if you need to do this in Tableau it can be accomplished like this:
DATEADD(
"day"
,CASE LEFT(LOWER(DATENAME("weekday",[DateFieldUsed])), 3)
WHEN 'fri' THEN 3
WHEN 'sat' THEN 2
ELSE 1
END
,[DateFieldUsed]
)
Basically, if it is Friday you need to add 3 days to the date, Saturday you need to add, and in any other situations just add 1 date. (please test, not doing this in Tableau so the numbers may be off).
I may have misunderstood the question, the example isn't exactly what you're asking. If your current value is 6/2/2021, and you are trying to find the week day of 6/2/2020, I would do this:
DATENAME("weekday", DATEADD(year, -1, [DateFieldUsed])

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.

PLSQL - How to find Monday and Friday of the week of a given date

I have spent days trying to figure this out to no avail, so hopefully someone can help me. I have a queried date set which contains several fields including a column of dates. What I want to do is create a new field in my query that tells what the Monday and Friday is for the week of that row's particular date.
So for example; if the date in one of my rows is "1/16/18",
the new field should indicate "1/15/18 - 1/19/18".
So basically I need to be able to extract the Monday date (1/15/18) and the Friday date (1/19/18) of the week of 1/16/18 and then concatenate the two with a dash ( - ) in between. I need to do this for every row.
How on earth do I do this? I've been struggling just to figure out how to find the Monday or Friday of the given date...
Assuming that your column is of type date, you can use trunc to get the first day of the week (monday) and then add 4 days to get the friday.
For example:
with yourTable(d) as (select sysdate from dual)
select trunc(d, 'iw'), trunc(d, 'iw') + 4
from yourTable
To format the date as a string in the needed format, you can use to_char; for example:
with yourTable(d) as (select sysdate from dual)
select to_char(trunc(d, 'iw'), 'dd/mm/yy') ||'-'|| to_char(trunc(d, 'iw') + 4, 'dd/mm/yy')
from yourTable
gives
15/01/2018-19/01/18
There may be a simpler, canonical Oracle method to this but you can still reduce it to a simple calculation on your own either way. I'm going to assume you're dealing with only dates falling Monday through Friday. If you do need to deal with weekend dates then you might have to be more explicit about which logical week they should be attached to.
<date> - (to_char(<date>, 'D') - 2) -- Monday
<date> + (6 - to_char(<date>, 'D')) -- Friday
In principle all you need to do is add/subtract the appropriate number of days based on the current day of week (from 1 - 7). There are some implicit casts going on in there and it would probably be wise to handle those better. You might also want to check into NLS settings to make sure you can rely on to_char() using Sunday as the first day of week.
https://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements004.htm
You can also use the NEXT_DAY function, as in:
SELECT TRUNC(NEXT_DAY(SYSDATE, 'MON')) - INTERVAL '7' DAY AS PREV_MONDAY,
TRUNC(NEXT_DAY(SYSDATE, 'FRI')) AS NEXT_FRIDAY
FROM DUAL;
Note that using the above, on weekends the Monday will be the Monday preceding the current date, and the Friday will be the Friday following the current date, i.e. there will be 11 days between the two days.
You can also use
SELECT TRUNC(NEXT_DAY(SYSDATE, 'MON')) - INTERVAL '7' DAY AS PREV_MONDAY,
TRUNC(NEXT_DAY(SYSDATE, 'MON')) - INTERVAL '3' DAY AS NEXT_FRIDAY
FROM DUAL;
in which case the Monday and Friday will always be from the same week, but if SYSDATE is on a weekend the Monday and Friday returned will be from the PREVIOUS week.

Wrong US week number calculation for 1st jan using datepart

SQL server DATEPART function has two options to retrieve week number;
ISO_WEEK and WEEK. I Know the difference between the two, I want to have week numbers based on Sunday start standard as followed in the US; i.e. WEEK. But it doesn't handles partial weeks the way I expected. e.g.
SELECT DATEPART(WEEK,'2015-12-31') --53
SELECT DATEPART(WEEK,'2016-01-01') --1
SELECT DATEPART(WEEK,'2016-01-03') --2
gives two different week numbers for a single week, divided in two years. I wanted to implement something like in the following link for week days.
Week numbers according to US standard
Basically I would like something like this;
SELECT DATEPART(WEEK,'2015-12-31') --1
SELECT DATEPART(WEEK,'2016-01-01') --1
SELECT DATEPART(WEEK,'2016-01-03') --2
EDIT:
Basically I am not good with the division of a single week into two, I have to perform some calculations based on week numbers and the fact that a single week to be divided isn't acceptable. So if above isn't possible.
Is it possible that the week number one would start from 2016-01-03. i.e. what I would in that case would be something like this:
SELECT DATEPART(WEEK,'2015-12-31') --53
SELECT DATEPART(WEEK,'2016-01-01') --53
SELECT DATEPART(WEEK,'2016-01-03') --1
If you want the US numbering, you can do this by taking the WEEK number of the end of the week rather than the date itself.
First ensure that the setting for first day of the week is in fact Sunday on your system. You can verify this by running SELECT ##DATEFIRST; this should return 7 for Sunday. If it doesn't, run SET DATEFIRST 7; first.
SELECT
end_of_week=DATEADD(DAY, 7-(DATEPART(WEEKDAY, '20151231')), '20151231'),
week_day=DATEPART(WEEK, DATEADD(DAY, 7-(DATEPART(WEEKDAY, '20151231')), '20151231'));
Which will return 2016/01/02 - 1.
If you wish generate week number of a date, it will return the week number of the year(input date)
Thus, I think sql server treat '2015-12-31' as the last week of 2015.

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.