Creating a week_ref number to pass into a stored procedure - sql

Currently one of the reports reads the month_ref which is created like this:
((DATEPART(yy, month_date) - 1200) * 100) + DATEPART(mm, month_date) AS month_ref,
month_date, DATENAME(MONTH, month_date) + ' ' + DATENAME(YEAR, month_date) AS month_name
I would like to create something like a week_ref?
The month ref uniqely identifies the month for the year. When its passed into a particular stored procedure, the sp will filter the results based on the month ref.
I am now wanting to create a weekly report - (mon - sun) and need to uniquely identify the week_ref so i can filter the results using the sp.
How can i do this?

This will give you a unique number for each week from monday to sunday and it doesn't depend on datefirst.
SELECT datediff(day, 0, month_date) / 7 week_ref FROM <table>
This will return an integer always as tested here:
SELECT SQL_VARIANT_PROPERTY(datediff(day, 0, getdate()) / 7, 'BaseType')
Returns:
int

Although I'd consider this technique very dirty, for months it does work. This is because there are always 12 months in a year.
For weeks it's both dirty and flawed. Some years have more weeks than others, because some weeks span more than one year.
I would recommend instead just using DATEDIFF().
Depending on the day-of-week that you want your weeks to start on, you need to do a little bit of calculation...
- Sun as start of week = DATEDIFF(WEEK, -1, yourDate )
- Mon as start of week = DATEDIFF(WEEK, -1, yourDate-1)
- Tue as start of week = DATEDIFF(WEEK, -1, yourDate-2)
- Wed as start of week = DATEDIFF(WEEK, -1, yourDate-3)
- Thu as start of week = DATEDIFF(WEEK, -1, yourDate-4)
- Fri as start of week = DATEDIFF(WEEK, -1, yourDate-5)
- Sat as start of week = DATEDIFF(WEEK, -1, yourDate-6)
I also recommend using this for your month calculations. DATEDIFF(MONTH, <a base date>, <your date>), the current one is really clunky.
EDIT Examples to turn the values above back into DATETIME
- Sun as start of week = DATEADD(WEEK, DATEDIFF(WEEK, -1, yourDate ), -1 )
- Mon as start of week = DATEADD(WEEK, DATEDIFF(WEEK, -1, yourDate-1), -1+1)
- Tue as start of week = DATEADD(WEEK, DATEDIFF(WEEK, -1, yourDate-2), -1+2)
- Wed as start of week = DATEADD(WEEK, DATEDIFF(WEEK, -1, yourDate-3), -1+3)
- Thu as start of week = DATEADD(WEEK, DATEDIFF(WEEK, -1, yourDate-4), -1+4)
- Fri as start of week = DATEADD(WEEK, DATEDIFF(WEEK, -1, yourDate-5), -1+5)
- Sat as start of week = DATEADD(WEEK, DATEDIFF(WEEK, -1, yourDate-6), -1+6)

Use
Select DATEPART(wk, GetDate()) --In your case month_date and not GetDate()
to get the week of the year back, and then you can use any formula you like to create a week_ref, but from what I can see from your edit, this whould the only thing that you need. However, you would change your month_ref to something like this.
((DATEPART(yy, month_date) - 1200) * 10000) + (DATEPART(mm, month_date) * 100) + DATEPART(wk, month_date) AS month_ref
Then you don't have to add an extra column

Use a calendar table with (at least) 3 columns: base_date, month_ref and week_ref. Then to get the month and week references (whatever those are) for a certain date, you can query them directly from the calendar table without using hard-to-read nested functions or other 'non-obvious' code:
select week_ref, month_ref
from dbo.calendar
where base_date = #my_date
You haven't explained what week_ref and month_ref actually mean, but if they are just numbers then a calendar table has the significant advantage that it can support mutliple different definitions. For example, you might want to support both the ISO week number and your own, internal week number scheme. You can also easily change values in the table if your logic changes, without changing any code.
As a general observation, a calendar table is usually a better solution than inline functions, especially if your requirements involve reporting.

Related

Get date for Saturday two weeks ago

I'm currently building a query which needs to show data from Saturday to Friday. For example, running the query today you should get data from 7/24 to 7/30. I’m seeing data from 7/25 to 7/30 and I frankly don’t know how to fix the code below to get Saturday’s data as well.
Here’s what I have:
WHERE
InvoiceDate BETWEEN DATEADD(WEEK, -2, DATEADD(WEEK, DATEDIFF(WEEK, 5, GETDATE()), 5))
AND DATEADD(DAY, -3, DATEADD(WEEK, DATEDIFF(WEEK, 0, GETDATE()), 0))
Preferably, I’d like to keep the similar format rather than parameterizing the query. Unless that’s a better idea of course! I’m also asking this on my phone so I apologize for not including the entire query. However because it is in the where clause, I figured the rest wasn’t needed.
you're leaving out a lot of information so assuming that you are running this query every Monday (as of my reply, today is Monday) and you are just going back to last-last Saturday to last Friday, your WHERE clause can be quite simple:
where InvoiceDate between dateadd(day,-9,getdate()) and dateadd(day,-3,getdate())
if there are are more criteria or conditions then let us know.
try the following query, just put the date whenever you need
SELECT
case
when datepart(weekday, '2021/08/03') >5
then DATEADD(DAY, +4, DATEADD(WEEK, DATEDIFF(WEEK, 0, '2021/08/03'), 0))
else DATEADD(DAY, -9, DATEADD(WEEK, DATEDIFF(WEEK, 0, '2021/08/03'), 0))
end AS last_saturday,
case
when datepart(weekday, '2021/08/03') >5
then DATEADD(DAY, +4, DATEADD(WEEK, DATEDIFF(WEEK, 0, '2021/08/03'), 0))
else DATEADD(DAY, -3, DATEADD(WEEK, DATEDIFF(WEEK, 0, '2021/08/03'), 0))
end AS last_friday;
I realize you have an answer already, but this will allow you to use whatever date you want. Using the day of the week to subtract days from today will give you the previous Saturday. Subtracting 7 from that will give you the Saturday a week ago.
So given that, the below will search the range from the start of a week ago Saturday until the start of this previous Saturday. This works with both date and datetime data types.
WHERE InvoiceDate >= DATEADD(day, -7 + DATEPART(dw,GETDATE()) * -1, GETDATE())
AND InvoiceDate < DATEADD(day, DATEPART(dw,GETDATE()) * -1, GETDATE())

SQL get previous month (in January too)

Hello I'm looking for simple way, how to get data from previous month. I get this code but it didn't work in January (result is 12 2021 and I need 12 2020)
select month(dateadd(month,-1,getdate())), year(getdate())
Presumably, you have some sort of date column.
In SQL Server, you can express this concept using datediff():
where datediff(month, datecol, getdate()) = 1
However, that is not "sargable", meaning that it prevents the use of indexes. So, I would instead recommend:
where datecol < datefromparts(year(getdate()), month(getdate()), 1) and
datecol >= dateadd(month, 1, datefromparts(year(getdate()), month(getdate()), 1))
If you simply want the first day of the previous month, you can use:
dateadd(month, 1, datefromparts(year(getdate()), month(getdate()), 1))
Try This
select CASE WHEN month(getdate())>1 THEN month(getdate())-1 ELSE 12 END ,
CASE WHEN month(getdate())>1 THEN YEAR (getdate()) ELSE YEAR (getdate()) -1 END
Using the answer given here: How can I select the first day of a month in SQL?
SELECT dateadd(month,-1,DATEADD(month, DATEDIFF(month, 0, getdate()), 0)) as previousmonth;
output:
2020-12-01 00:00:00.000
I can provide next query using FORMAT function:
SELECT
-- get current day in previous month
FORMAT(dateadd(month, -1, getdate()), 'yyyy-MM-dd') as current_previousmonth,
-- get first of previous month
FORMAT(dateadd(month, -1, getdate()), 'yyyy-MM-01') as first_previousmonth,
-- previous month without date
FORMAT(dateadd(month, -1, getdate()), 'yyyy-MM') as previousmonth;
test T-SQL here
Here you go!
select dateadd(mm,-1,eomonth(getdate())) as [Previous Month]
Result:
Previous Month
--------------
2020-12-31
You could also use CONVERT() or FORMAT() functions to format the date as you desire.
Try
SELECT FORMAT(DATEADD(month, -1, GETDATE()),'MM/yyyy');
It will give you previous month and the year. If you are comparing to a date column in a existing table, then you need the date part too as you want to know December of which year was the previous month. But if you don't want the year, then just adjust the 'MM/yyyy' part to suit your purpose.

Explain Query Logic - Get First Wednesday of Current Month

SELECT
DATEADD(WEEK, DATEDIFF(WEEK, 0,DATEADD(DAY, 6 - DATEPART(DAY, GETDATE()),
GETDATE())), 0),'First Monday of Current Month'
This query returns the first Monday of the current month. I just want to know how this query is working and how do I get the first Wednesday of the current month instead.
Let's simplify the whole:
SELECT DATEADD(WEEK, DATEDIFF(WEEK, 0, DATEADD(DAY, 6 - DATEPART(DAY, GETDATE()), GETDATE())), 0)
you can think at it in this way:
-- number of day to go back to reach 1st week of month
z = 6 - DATEPART(DAY, GETDATE())
-- a day in 1st week of the month
y = DATEADD(DAY, z, GETDATE())
-- number of weeks between 0 (1900-01-01) and 1st week of month
x = DATEDIFF(WEEK, 0, y)
-- add the number of weeks elapsed to 1900-01-01 to get the datetime of 1st day of 1st week of month
SELECT DATEADD(WEEK, x, 0)
I just want to know how this query is working
SELECT DATENAME(WEEKDAY, '1900-01-01') --'Monday'
SELECT DATENAME(WEEKDAY, 0) --also 'Monday'
January 1, 1900 was a Monday. When you add a week to a Monday you get another Monday. If you add 6,170 weeks to a Monday- you still get a Monday. As of 04/10/2018 there have been 6,170 weeks since Jan 1, 1900.
Simply, the query calculates these weeks, adding 6,170 weeks since Monday, Jan 1 1900.
how do I get the first Wednesday of the current month instead?
SELECT DATENAME(WEEKDAY, '1900-01-03') --Wednesday
SELECT DATENAME(WEEKDAY, 2) --also Wednesday
January 3, 1900 is represented by integer 2. We changed a 0 (which was monday) to a 2 (wednesday). If you add 6,170 weeks to a Wednesday you still get a Wednesday.
In the query there is a 0. We can change this to a 2:
SELECT
DATEADD(WEEK, DATEDIFF(WEEK, 0,DATEADD(DAY, 6 - DATEPART(DAY, GETDATE()),
GETDATE())), 2),'First Wednesday of Current Month'
Edit: I can make this perhaps a little clearer by getting rid of the integer and putting in the actual date:
SELECT
DATEADD(WEEK, DATEDIFF(WEEK, 0,DATEADD(DAY, 6 - DATEPART(DAY, GETDATE()),
GETDATE())), '1900-01-03'),'First Wednesday of Current Month'
This will give you the first Wednesday of the month, as requested in your comment:
SELECT
DATEADD(WEEK, DATEDIFF(WEEK, 0,DATEADD(DAY, 6 - DATEPART(DAY, GETDATE()), GETDATE())), 2)
AS 'First Wednesday of Current Month'
I changed your last 0 in the DATEADD function to a 2, as this is a zero based representation of the days of the week, 0 being Monday.
You can use the "Try it yourself" functionality on W3schools to play around with queries and figure them out: W3schools. Just paste your query in the console.
I tried many formula to get first Wednesday of the current month including above scripts but they were not working right if the month starts with Wednesday. (2022-06-01 can be tried). So I succeed it with my own way, you can see the sql below.
select
FirstWednesdayofCurrentMonth =
case when datepart(dw,EOMONTH(dateadd(month,-1,getdate()))) = 3
then dateadd(dd,1,EOMONTH(dateadd(month,-1,getdate()))) -- if month start with wednesday
else convert(date, DATEADD(DAY,(DATEDIFF(DAY,2,DATEADD(d,1,EOMONTH(dateadd(month,-1,getdate())))) / 7) * 7 + 7, 2)) -- if not
end

Function to go back 2 years, first day of last month

I'm hoping to find a solution for this to automate a report I have. Basically what I'm trying to accomplish here is grabbing a date (first day of previous month, two years ago through last day of previous month current year).
So the date span if running this month would look like this: between 4/1/2013 and 3/31/2015
I have found code to get the date two years ago but I'm not able to also incorporate the month functions... Any help is very much appreciated!
For year I'm using this:
SELECT CONVERT(VARCHAR(25),DATEADD(year,-2,GETDATE()),101)
First day of previous month 2 years ago:
SELECT CONVERT(DATE,dateadd(day, -1, dateadd(day, 1 - day(GETDATE()), GETDATE())))
Last day of last month:
SELECT CONVERT(DATE,DATEADD(month, DATEDIFF(month, 0, DATEADD(year,-2,GETDATE())), 0))
Then just do whatever logic you need with them
Your where clause can look something like this:
where date >= cast(dateadd(year, -2,
dateadd(month, -1, getdate() - day(getdate()) + 1)
) as date) and
date < cast(getdate() - day(getdate()) + 1 as date)
This makes use of the handy convenience that subtracting/adding a number to a datetime is the same as adding a date. The start date says: get the first day of the month, then subtract one month, then subtract two years. This could have been done as dateadd(month, -25, . . .), but I think separating the logic is clearer.
This gives you two dates you are looking for:
SELECT
CAST((DATEADD(yy, -2, DATEADD(d, -1 * DATEPART(dd, getdate()) + 1 , GETDATE() ))) as date) as yourTwoYearsAgoDate,
CAST((DATEADD(d, -1 * DATEPART(dd, GETDATE()), GETDATE())) as date) as yourEndOfLastMonthDate
Given a reference date (e.g. "today"),
declare #today date = '23 April 2015'
The 1st of the month is computed by subtracting 1 less than the day number of the current month:
select first_of_current_month = dateadd(day,1-day(#today),#today)
The last day of the previous month is day 0 of the current month, so to get the last day of the previous month, just subtract the current day number:
select last_of_previous_month = dateadd(day,-day(#today),#today)
Moving two years back is easy:
select two_years_back = dateadd(year,-2, #today )
Putting it all together, this should do you:
declare #today date = '23 April 2015'
select *
first_day_of_current_month = dateadd(day,1-day(#today),#today),
last_day_of_previous_month = dateadd(day, -day(#today),#today) ,
date_from = dateadd(year,-2, dateadd(day,1-day(#today),#today) ) ,
date_thru = dateadd(day, -day(#today),#today)
yielding the expected results:
first_day_of_current_month: 2015-04-01
last_day_of_previous_month: 2015-03-31
date_from : 2013-04-01
date_thru : 2015-03-31
So you should be able to say something like this:
select *
from foo t
where t.transaction_date between dateadd(year,-2, dateadd(day,1-day(#today),#today) )
and dateadd(day, -day(#today),#today)
If you have to deal with datetime values rather than date, its easier to not use between and say something like this:
declare #today date = current_timestamp -- get the current date without a time component
select *
from foo t
where t.transaction_date >= dateadd(year,-2, dateadd(day,1-day(#today),#today) )
and t.transaction_date < dateadd(year, 0, dateadd(day, -day(#today),#today)
[superfluous addition of 0 years added for clarity]

Keyword for "Last Month" in SQL Server 2008

I have a query (pasted below), and I would like to make it so that people don't need to update the completed date range. I would like for it to automatically just get results from last month. So if it is run in February, for example, it will give me results for all completed items that meet my criteria for January. Can anyone think of a way to do that?
select External_ID__c,
Ewrk_Tracking_Number__c,
PIF_Branch_Name,
Distribution_Branch_Name,
Transaction_Type__C,
submitter_date__c, Completed_Date__C,
COUNT(External_ID__c)
from Business_Solutions_D.dbo.Reporting_SalesForce_AspireBaseData
where PIF_Branch_Code = 977
and Completed_Date__C >= '2015-01-01'
and Completed_Date__C < '2015-02-01'
and Delete_Flag__C = 'FALSE'
group by External_ID__c,
Ewrk_Tracking_Number__c,
PIF_Branch_Name,
Distribution_Branch_Name,
Transaction_Type__C,
submitter_date__c,
Completed_Date__C
There is no "keyword" for last month. You have to put that in your predicates.
Here is an example of how to get some date values for this.
select dateadd(MONTH, datediff(MONTH, 0, GETDATE()), 0) as BeginningOfThisMonth
select dateadd(MONTH, datediff(MONTH, 0, GETDATE()) - 1, 0) as BeginningOfPreviousMonth
If you want to see a number of other date routines here is an excellent blog post with quite a few of them. http://www.sqlservercentral.com/blogs/lynnpettis/2009/03/25/some-common-date-routines/
If you mean the last month prior to this one, you can do it in two steps: first, find the first day of the current month
#firstDayOfThisMonth = DATEADD(day, DAY(GETDATE())-1, GETDATE())
then subtract one month:
#firstDayOfLastMonth = DATEADD(month, -1, #firstDayOfThisMonth)
Then your query would be:
and Completed_Date__C >= #firstDayOfLastMonth
and Completed_Date__C < #firstDayOfThisMonth
Another way would be to query where the difference (in months) between Completed_Date__C and the current date is 1:
and DATEDIFF(Completed_Date__C, GETDATE()) = 1
You can do this with date arithmetic. One trick to get the first date of the month is to subtract the current day of the month from the date and add one day. SQL Server allows you to do this with + and - instead of dateadd(), on a datetime value. Of course, you need to remove the time component as well (using cast( as date)).
The logic looks like this for the current month:
where Completed_Date__C >= cast(getdate() - day(getdate()) + 1 as date) and
Completed_Date__C < dateadd(month, 1, cast(getdate() - day(getdate()) + 1 as date))
And like this for the previous month:
where Completed_Date__C >= dateadd(month, -1, cast(getdate() - day(getdate()) + 1 as date)) and
Completed_Date__C < cast(getdate() - day(getdate()) + 1 as date)
This has the nice property that it is a sargeable as your original code, so it will take advantage of an index on the column, if appropriate.
You just need to have it do some date math to calculate it.
--Go to last day of prev month - 'Day' to account for varying month day counts
and Completed_Date__C >= GETDATE() - DATEPART(DAY, GETDATE()) - DATEPART(DAY, GETDATE() - DATEPART(DAY, GETDATE())) + 1
and Completed_Date__C < GETDATE() - DATEPART(DAY, GETDATE()) + 1
When you do additions on DateTimes + integer it assumes it day based addition.