SQL DateDiff Weeks - Need and alternative - tsql

The MS SQL DateDiff function counts the number of boundaries crossed when calculating the difference between two dates.
Unfortunately for me, that's not what I'm after. For instance, 1 June 2012 -> 30 June 2012 crosses 4 boundaries, but covers 5 weeks.
Is there an alternative query that I can run which will give me the number of weeks that a month intersects?
UPDATE
To try and clarify exactly what I'm after:
For any given month I need the number of weeks that intersect with that month.
Also, for the suggestion of just taking the datediff and adding one, that won't work. For instance February 2010 only intersects with 4 weeks. And the DateDiff calls returns 4, meaning that simply adding 1 would leave me the wrong number of weeks.

Beware: Proper Week calculation is generally trickier than you think!
If you use Datepart(week, aDate) you make a lot of assumptions about the concept 'week'.
Does the week start on Sunday or Monday? How do you deal with the transition between week 1 and week 5x. The actual number of weeks in a year is different depending on which week calculation rule you use (first4dayweek, weekOfJan1 etc.)
if you simply want to deal with differences you could use
DATEDIFF('s', firstDateTime, secondDateTime) > (7 * 86400 * numberOfWeeks)
if the first dateTime is at 2011-01-01 15:43:22 then the difference is 5 weeks after 2011-02-05 15:43:22
EDIT: Actually, according to this post: Wrong week number using DATEPART in SQL Server
You can now use Datepart(isoww, aDate) to get ISO 8601 week number. I knew that week was broken but not that there was now a fix. Cool!
THIS WORKS if you are using monday as the first day of the week
set language = british
select datepart(ww, #endofMonthDate) -
datepart(ww, #startofMonthDate) + 1
Datepart is language sensistive. By setting language to british you make monday the first day of the week.
This returns the correct values for feburary 2010 and june 2012! (because of monday as opposed to sunday is the first day of the week).
It also seems to return correct number of weeks for january and december (regardless of year). The isoww parameter uses monday as the first day of the week, but it causes january to sometimes start in week 52/53 and december to sometimes end in week 1 (which would make your select statement more complex)

SET DATEFIRST is important when counting weeks. To check what you have you can use select ##datefirst. ##datefirst=7 means that first day of week is sunday.
set datefirst 7
declare #FromDate datetime = '20100201'
declare #ToDate datetime = '20100228'
select datepart(week, #ToDate) - datepart(week, #FromDate) + 1
Result is 5 because Sunday 28/2 - 2010 is the first day of the fifth week.
If you want to base your week calculations on first day of week is Monday you need to do this instead.
set datefirst 1
declare #FromDate datetime = '20100201'
declare #ToDate datetime = '20100228'
select datepart(week, #ToDate) - datepart(week, #FromDate) + 1
Result is 4.

Related

Find last day of the previous week in Teradata?

I want to find out the previous weeks's last day in Teradata SQL using Sunday as the last day of the week. For example, today is Friday 1/27, so the last week ended on Sunday (1/22) and I would want to return 2023-01-22.
Other examples:
If current date is '2023-01-02', then the output I require is '2023-01-01'
If current date is '2023-01-18', then the output I require is '2023-01-15'
With Hive query I would use:
date_sub(current_date, cast(date_format(current_date, 'u') as int));
What would the equivalent be in Teradata? I've tried using the code below but it seems to return the date of the closest Sunday instead of the date of the previous Sunday.
SELECT ROUND(current_date, 'd') (FORMAT 'yyyy-mm-dd');
There are several ways:
Probably the best one is one of the built-in functions to return the previous xxxday <= the input date:
Td_Sunday(Current_Date - 1)
Or the function to return the next xxxday > input date:
Next_Day(Current_Date - 8, 'sun')
Truncating is least understandable:
Trunc(Current_Date, 'IW') -1
TRUNC supports three variations, only IW is usable, but restricted to Monday as week start:
IW: the Monday of the ISO week
WW: the same day of the week as January 1st of the year
W: the same day of the week as the first day of the month
You can use the trunc function to return the first day of the a week, month, ect.
select trunc(current_date -7 ,'IW')
Current date today is 2023-01-27. This will return 2023-01-15, the previous Sunday.
EDIT: Sorry, meant to use the ISO week. As Dnoeth points out, the regular week option doesn't work consistently (which I didn't know, never used it for this before). Anyhoo, his answer is better than mine...

TSQL ISO Month Week Number for ISO Year Week Number

Using TSQL I need to get the ISO Week Number in a Month for a give ISO Year Week Number.
For example: The following code will give me Week #1 for 12/31/2001, which is correct. It is the first Monday in 2002 and the first day of the ISO Year 2002.
select DATEPART(ISO_WEEK, '12-31-2001'); --Week 1 January 2002
My question is how do I...
(1) Take the ISO Week Number Example: ISO Year Week Number: 14 for April 4, 2016 (April Week #1).
(2) Now Take ISO Year Week Number 14 and return April Month Week Number = 1 for the example above.
There seems to be nothing in SQL Server to get the ISO Month Week# from the ISO Year Week Number. I have a function I wrote but it is has some hacks to get it to work, but not 100%.
I think you want something like this... but am not sure why you need the ISO_WEEK. Just replace getdate() with your column.
select datepart(wk, getdate()) - datepart(wk,dateadd(m, DATEDIFF(M, 0, getdate()), 0)) + 1
After attempting to handle getting ISO Month Week Number in functions I decided an easier solution was to create an ISO_Calendar table in SQL Sever.
We know in TSQL you can get the ISO Year Week Number and some a bit of work the ISO Year Number. The ISO Month Week Number is another story.
I build the table shown below with data from 2000 to 2040 by populating all the columns other than the ISO Month number. Then on a second pass I looped through the table and set the ISO Month number based on the Month# in the Monday Date.
Now if I want to get the ISO Month number for a date I check #Date between Monday and Sunday. In my case I am only concerned with dates between Monday and Friday since this is for a stock analysis site.
select #ISOMonthWeekNo = c.ISOMonthWeekNo
from ISO_Calendar c
where #TransDate between c.Monday and c.Sunday;
The advantage is the table is a one time build and easier to verify the accuracy of the data.

Between Date Time T-SQL

I have the following Where clause which is causing me issues and I am looking for a work around.
#startDate is the todays date and #endDate is the end date which could be 7 days, 14 days or 20 days in the future, this works fine unless the end month is greater than the start month.
ISSUE- if the StartDate DAY is 20 and the END Date Day is in the next Month example Start Day is 10/21 and End Day is 11/5 than the where clause cancels its self out, I can't use a Between because we are not including the yr.
I tried an OR but this also doesn't work.
WHERE DAY(t.AnniversaryDate) >= DAY(#startDate)
AND DAY(t.AnniversaryDate) <= DAY(#endDate)
AND MONTH(t.AnniversaryDate) >= MONTH(#startDate)
AND MONTH(t.AnniversaryDate) <= MONTH(#endDate)
AND YEAR(t.AnniversaryDate) < YEAR(GETDATE())
The expression
select DATEADD(year,DATEDIFF(year,'19780517',GETDATE()),'19780517')
Will always return the 17th of May of the current year. A similar expression can be used to perform the same trick for any date1 by replacing both instances of '19780517' with the date of interest.
So, whatever "I can't use a Between because we are not including the yr" means, you should be able to work around it by using the above expression.
So, I think what you want would be:
WHERE DATEADD(year,
DATEDIFF(year,t.AnniversaryDate,GETDATE()),
t.AnniversaryDate)
BETWEEN #startDate and #endDate
1So long as you're happy that 29th February maps to 28th February if you ask for it in a non-leap year.

DB2 separate number of weeks per quarter from timestamp

I'm trying to separate weeks from timestamp per quarter so it should be between 1-13 week per quarter so I used function week() but it takes between 1-52 week as whole year so I made it to be divided by function of quarter like below
select Week (EVENTTIMESTAMP) / QUARTER (EVENTTIMESTAMP) from KAP
The thing here that results aren't accurate; for example it shows:
time stamp 2014-07-06 12:13:03.018
week number 9
which isn't correct because July is first month in Q3 and it's in the 6 days so it should be 1 week from Q3 not 9.
Any suggestion where it go wrong?
You want something like WEEK modulo 13 to get week number within a quarter. You will have to tinker with 'modulo 13 yields 0..12' by adding or subtracting one at appropriate points.
Some minimal Google searching using 'ibm db2 sql modulo' yields DB2 MOD function:
The MOD function divides the first argument by the second argument and returns the remainder.
Hence MOD(WEEK(...), 13), except you probably need MOD(WEEK(...)-1, 13) + 1, as intimated already.
You may need to watch for what the WEEK() function does at year ends:
The WEEK function returns an integer in the range of 1 to 54 that represents the week of the year. The week starts with Sunday, and January 1 is always in the first week.
I'm curious about how they can come up with week 54. I suppose it requires 1st January to be a Saturday (so 2nd January is the start of week 2) of a leap year, as in 2000 and 2028. Note that week 53 and (occasionally) week 54 will show up as weeks 1 and 2 of Q5 unless you do something. Also, Saturday 2000-03-25 would be the end of Q1 and Sunday 2000-03-26 would be the start of Q2 under the regime imposed by the WEEK() function and a simple MOD(WEEK(...), 13) calculation. You're likely to have to tune this to meet your real requirements.
There's also the WEEK_ISO() function:
The WEEK_ISO function returns an integer in the range of 1 to 53 that represents the week of the year. The week starts with Monday and includes seven days. Week 1 is the first week of the year that contains a Thursday, which is equivalent to the first week that contains January 4.
Note that under the ISO scheme, the 3rd of January can be in week 52 or 53 of the previous year, and the 29th of December can be in week 1 of the next year. Curiously, there doesn't seem to be a YEAR_ISO() function to resolve such ambiguities.
In a data warehouse, the proper solution to this is to create a time dimension that contains static mappings for days/weeks/months/quarters/years. This provides the ability to define these based on your business' fiscal calendar (if it is not following on the calendar year).
See: http://www.kimballgroup.com/1997/07/10/its-time-for-time/ for more information.

Need to sort by Date then Hour, then output Date, text Day of week , range of hours SQL Server 2008 R2

NEWBIE at work! I am trying to create a simple summary that counts the number of customer visits and groups by 1) date and 2) hour, BUT outputs this:
Date Day of Wk Hour #visits
8/12/2013 Monday 0 5
8/12/2013 Monday 1 7
8/12/2013 Monday 6 10
8/13/2013 Tuesday 14 25
8/13/2013 Tuesday 16 4
We are on military time, so 14 = 2:00 pm
Select
TPM300_PAT_VISIT.adm_ts as [Date]
,TPM300_PAT_VISIT.adm_ts as [Day of Week]
,TPM300_PAT_VISIT.adm_ts as [Hour]
,count(TPM300_PAT_VISIT.vst_ext_id) as [Total Visits]
From
TPM300_PAT_VISIT
Where
TPM300_PAT_VISIT.adm_srv_cd='22126'
and TPM300_PAT_VISIT.adm_ts between '07-01-2013' and '08-01-2013'
Group by
cast(TPM300_PAT_VISIT.adm_ts as DATE)
,datepart(weekday,TPM300_PAT_VISIT.adm_ts)
,datepart(hour,TPM300_PAT_VISIT.adm_ts)
Order by
CAST(TPM300_PAT_VISIT.adm_ts as DATE)
,DATEPART(hour,TPM300_PAT_VISIT.adm_ts)
This should solve the problem:
; With Streamlined as (
SELECT
DATEADD(hour,DATEDIFF(hour,'20010101',adm_ts),'20010101') as RoundedTime,
vst_ext_id
from
TPM300_PAT_VISIT
where
adm_srv_cd='22126' and
adm_ts >= '20130701' and
adm_ts < '20130801'
)
Select
CONVERT(date,RoundedTime) as [Date],
DATEPART(weekday,RoundedTime) as [Day of Week],
DATEPART(hour,RoundedTime) as [Hour],
count(vst_ext_id) as [Total Visits]
From
Streamlined
Group by
RoundedTime
Order by
CONVERT(date,RoundedTime),
DATEPART(hour,RoundedTime)
In the CTE (Streamlined)'s select list, we floor each adm_ts value down to the nearest hour using DATEADD/DATEDIFF. This makes the subsequent grouping easier to specify.
We also specify a semi-open interval for the datetime comparisons, which makes sure we include everything in July (including stuff that happened at 23:59:59.997) whilst excluding events that happened at midnight on 1st August. This is frequently the correct type of comparison to use when working with continuous data (floats, datetimes, etc), but means you have to abandon BETWEEN.
I'm also specifying the dates as YYYYMMDD which is a safe, unambiguous format. Your original query could have been interpreted as either January 7th - January 8th or 1st July - 1st August, depending on the settings of whatever account you use to connect to SQL Server. Better yet, if these dates are being supplied by some other (non-SQL) code, would be for them to be passed as datetimes in the first place, to avoid any formatting issues.