Wrong US week number calculation for 1st jan using datepart - sql

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.

Related

Improper calculation of a date difference in sql

I need to calculate the difference between DFU.HISTSTART and the last Sunday which is for today is 2/27. It should be dynamic and change every Sunday.
For some reason for this calculation I am getting 3 and should get 4.
,ABS(DATEDIFF(wk,
DATEADD(wk,
DATEDIFF(wk,6,GETDATE()), 0), DFU.HISTSTART))
AS '#WKS of Hist'
Does someone have any ideas?
You have two problems... the first is that you're trying to do the old offset trick with the "6". That works on other date parts but not on week. From the Microsoft Documentation...
For a week (wk, ww) or weekday (dw) datepart, the DATEPART return
value depends on the value set by SET DATEFIRST.
If your DATEFIRST is set to 7 (you can verify by running SELECT ##DATEFIRST;) AND your weeks start on Sundays, the following will work just fine and return a "4".
--===== Setup just the dates in question for a demo
DECLARE #HistStart DATE = '01-30-22'
,#Today DATE = '02-27-22'
;
--===== Demo the "right" way to use "wk".
-- I say "right" way because I don't trust DATEFIRST.
SELECT DATEDIFF(wk,#HistStart,#Today)
;
GO
The second thing is that it's generally a really bad practice to depend on the DATEFIRST setting in this global computing environment. Instead, do the much more universal/bullet-proof method of using Integer math to calculate the number of weeks it's been since date-serial 6, which you correctly identified as a Sunday.
--===== Setup just the dates in question for a demo
DECLARE #HistStart DATE = '01-30-22'
,#Today DATE = '02-27-22'
;
--===== Demo "Bulletproof" Way to calculate the difference in Weeks starting on Sunday
SELECT DATEDIFF(dd,6,#Today)/7 - DATEDIFF(dd,6,#HistStart)/7
;
If you need to calculate week differences in weeks a lot, you might want to turn that into a function so that if the company decides to change the day of the week that is the start of the week, you'll only need to change it in one place. In fact, you might want to have the function read it (the date-serial for the starting day of the week) from a "general settings table".
Another way of doing this:
with last_sunday as (
SELECT
case DAYNAME(current_date())
when 'Sun' then current_date()
when 'Mon'then current_date()-1
when 'Tue'then current_date()-2
when 'Wed'then current_date()-3
when 'Thu'then current_date()-4
when 'Fri'then current_date()-5
when 'Sat'then current_date()-6
else '2020-01-01' end "SUNDAY_DATE"
)
SELECT
DFU.HIST_START_DATE
,LAST_SUNDAY.SUNDAY_DATE
,datediff(week,DFU.HIST_START_DATE,LAST_SUNDAY.SUNDAY_DATE) weeks_diff
FROM DFU
JOIN LAST_SUNDAY
;

SQL calculate number of days in month excluding weekends and holidays days

I have approximately the same table (excluding count column). I want to calculate the number of working days (Mon-Fri) and exclude public holidays.
I tried to try the following query
SELECT count(distinct(date)) from MYDB where dummy <> 1
However, it gives the only total number of days including weekends. Additionally, if use this command it counts distinct dates, however, my dates do not show a full month, so another logic should've used. Could you help to figure out which code is better to use?
there should be a function in Vertica that extracts weekday from date, so to exclude weekends you'll need to add another condition like
extract(dow from date) not in (6,0)
(6 is Sat, 0 is Sun in this case)

How do I get the number of days in a month for the specific date in that row of data using SQL?

For example, if I have a data set including two columns, one which shows the month as a number and the other which shows the year (result of grouping my data using GROUP BY), I want to add another column called 'Days in the month' which will display the number of days in the respective month. Is there a way I can do this? Is there some function I can add in the SELECT clause?
I want to do this since there are further calculations I need to do with that number for each row.
In SQL Server 2012+, you can use:
select day(eomonth(datecol))
eomonth() gets the last day of the month. day() just returns the day of the month -- the number of days in the month, in this case.
For older SQL Server versions, I use the following:
DAY(DATEADD(MONTH, DATEDIFF(MONTH, -1, date_column)- 1, -1))
Much less elegant than the previous answer, but functional.

SQL ORACLE Get week numbers from multiple datetime rows

I have 70.000 rows of data, including a date time column (YYYY-MM-DD HH24-MM-SS.).
I want to split this data into 3 separate columns; Hour, day and Week number.
The date time column name is 'REGISTRATIONDATE' from the table 'CONTRACTS'.
This is what I have so far for the day and hour columns:
SELECT substr(REGISTRATIONDATE, 0, 10) AS "Date",
substr(REGISTRATIONDATE, 11, 9) AS "Hour"
FROM CONTRACTS;
I have seen the options to get a week number for specific dates, this assignment concerns 70.000 dates so this is not an option.
You (the OP) still have to explain what week number to assign to the first few days in a year, until the first Monday of the year. Do you assign a week number for the prior calendar year? In a Comment I asked about January 1, 2017, as an example; that was a Sunday. The week from January 2 to January 8 of 2017 is "week 1" according to your definition; what week number do you assign to Sunday, January 1, 2017?
The straightforward calculation below assigns to it week number 0. Other than that, the computation is trivial.
Notes: To find the Monday of the week for any given date dt, we can use trunc(dt, 'iw'). iw stands for ISO Week, standard week which starts on Monday and ends on Sunday.
Then: To find the first Monday of the year, we can start with the date January 7 and ask for the Monday of the week in which January 7 falls. (I won't explain that one - it's easy logic and it has nothing to do with programming.)
To input a fixed date, the best way is with the date literal syntax: date '2017-01-07' for January 7. Please check the Oracle documentation for "date literals" if you are not familiar with it.
So: to find the week number for any date dt, compute
1 + ( trunc(dt, 'iw') - trunc(date '2017-01-07', 'iw') ) / 7
This formula finds the Monday of the ISO Week of dt and subtracts the first Monday of the year - using Oracle date arithmetic, where the difference between two dates is the number of days between them. So to find the number of weeks we divide by 7; and to have the first Monday be assigned the number 1, instead of 0, we need to add 1 to the result of dividing by 7.
The other issue you will have to address is to convert your strings into dates. The best solution would be to fix the data model itself (change the data type of the column so that it is DATE instead of VARCHAR2); then all the bits of data you need could be extracted more easily, you would make sure you don't have dates like '2017-02-29 12:30:00' in your data (currently, if you do, you will have a very hard time making any date calculations work), queries will be a lot faster, etc. Anyway, that's an entirely different issue so I'll leave it out of this discussion.
Assuming your REGISTRATIONDATE if formatted as 'MM/DD/YYYY'
the simples (and the faster ) query is based ond to to_char(to_date(REGISTRATIONDATE,'MM/DD/YYYY'),'WW')
(otherwise convert you column in a proper date and perform the conversio to week number)
SELECT substr(REGISTRATIONDATE, 0, 10) AS "Date",
substr(REGISTRATIONDATE, 11, 9) AS "Hour",
to_char(to_date(REGISTRATIONDATE,'MM/DD/YYYY'),'WW') as "Week"
FROM CONTRACTS;
This is messy, but it looks like it works:
to_char(
to_date(RegistrationDate,'YYYY-MM-DD HH24-MI-SS') +
to_number(to_char(trunc(to_date(RegistrationDate,'YYYY-MM-DD HH24-MI-SS'),'YEAR'),'D'))
- 2,
'WW')
On the outside you have the solution previous given by others but using the correct date format. In the middle there is an adjustment of a certain number of days to adjust for where the 1st Jan falls. The trunc part gets the first of Jan from the date, the 'D' gets the weekday of 1st Jan. Since 1 represents Sunday, we have to use -2 to get what we need.
EDIT: I may delete this answer later, but it looks to me that the one from #mathguy is the best. See also the comments on that answer for how to extend to a general solution.
But first you need to:
Decide what to do dates in Jan before the first Monday, and
Resolve the underlying problems in the date which prevent it being converted to dates.
On point 1, if assigning week 0 is not acceptable (you want week 52/53) it gets a bit more complicated, but we'll still be able to help.
As I see it, on point 2, either there is something systematically wrong (perhaps they are timestamps and include fractions of a second) or there are isolated cases of invalid data.
Either the length, or the format, or the specific values don't compute. The error message you got suggests that at least some of the data is "too long", and the code in my comment should help you locate that.

Best way to break down by weeks in BigQuery

So what I'm looking to do is create a report that shows how many sales a company had on a weekly basis.
So we have a time field called created that looks like this:
2016-04-06 20:58:06 UTC
This field represents when the sale takes place.
Now lets say I wanted to create a report that gives you how many sales you had on a weekly basis. So the above example will fall into something like Week of 2016-04-03 (it doesn't have to exactly say that, I'm just going for the simplest way to do this)
Anyone have any advice? I imagine it involves using the UTEC_TO_xxxxxx functions.
The documentation advises to use standard SQL functions, like DATE_TRUNC():
SELECT DATE_TRUNC(DATE '2019-12-25', WEEK) as week;
you can use WEEK() function - it gives you week number
SELECT WEEK('2016-04-06 20:58:06 UTC')
if you need first day of the week - you can try something like
STRFTIME_UTC_USEC((UTC_USEC_TO_WEEK(TIMESTAMP_TO_USEC(TIMESTAMP('2016-05-02 20:58:06 UTC')), 0)),'%Y-%m-%d')
I had to add parentheses:
SELECT DATE_TRUNC(DATE('2016-04-06 20:58:06 UTC'), WEEK) as week;
This is quite an old question and things have moved on since.
In my case, I found that the old WEEK function is no longer recognised, so I had to instead use the EXTRACT function. The doc for it can be found here.
For me it was enough to just extract the ISOWEEK from the timestamp, which results in the week of the year (the ISOYEAR) as a number.
ISOWEEK: Returns the ISO 8601 week number of the datetime_expression. ISOWEEKs begin on Monday. Return values are in the range [1, 53]. The first ISOWEEK of each ISO year begins on the Monday before the first Thursday of the Gregorian calendar year.
So I did this:
SELECT EXTRACT(ISOWEEK FROM created) as week
And if you want to see the week's last day, rather than the week's number in a year, then:
SELECT last_day(datetime(created), isoweek) as week