Finding first Sunday of the month is not working - sql

I need to find first Sunday of the month. tried with next_day function which produced proper result, but if the first day of the month is a Sunday then it doesn't work.
select next_day(trunc(sysdate,'MM'),'sun') first_sun
from dual
select next_day(trunc(sysdate,'MM'),'sun') first_sun
from dual
I'm running the query with the date sysdate='2019-09-10' which shows the 2nd Sunday instead of the 1st Sunday.

Just go back a day after truncating, so you find the first Sunday after the last day of the previous month:
select next_day(trunc(sysdate,'MM') - 1,'sun') first_sun from dual;
FIRST_SUN
----------
2019-09-01

You happen to land on month when Sunday is also the first day in month,
NEXT_DAY uses later than date, therefore you will have to check from previous day for example
select next_day(trunc(sysdate,'MM')-1,'SUNDAY') first_sun from dual;
NEXT_DAY returns the date of the first weekday named by char that is later than the date date.

Related

Difference of timestamp event rows using WHERE clause

I have two event tables with timestamped data: Registered, Signed_In.
Both have rows such as: original_timestamp, user_id
I am trying to find out users who haven't signed in within 30 days after registering. I have used the following query but I cannot add a WHERE clause to it.
I tried a query but I am getting hourly difference, whereas I wanted days difference which is unsupported in BigQuery.
SELECT Signed_In.user_id, TIMESTAMP_DIFF(Registered.original_timestamp, Signed_In.original_timestamp, HOUR) AS days_difference
FROM `test_db.Signed_In` signed_in
JOIN `test_db.Registered` registered
ON Signed_In.user_id = Registered.user_id
GROUP BY 1,2
ORDER BY 2 DESC
WHERE days_difference > '30'
I am getting two columns: user_id, days_difference but the days_difference shows hours and my WHERE clause is rejected when I use it.
You can try this below code-
Note: Using Ordinal Position for GROUP BY and ORDER BY is not a good practice. Its always safe and standard to use the column names directly.
SELECT Signed_In.user_id,
TIMESTAMP_DIFF(Registered.original_timestamp, Signed_In.original_timestamp, HOUR) AS days_difference
FROM `test_db.Signed_In` signed_in
JOIN `test_db.Registered` registered
ON Signed_In.user_id = Registered.user_id
WHERE DATE_DIFF(Registered.original_timestamp, Signed_In.original_timestamp, Day) > '30'
GROUP BY 1,2
ORDER BY 2 DESC
Just replace HOUR to DAY in your query:
SELECT Signed_In.user_id, TIMESTAMP_DIFF(Registered.original_timestamp, Signed_In.original_timestamp, DAY) AS days_difference
Correct values are:
MICROSECOND
MILLISECOND
SECOND
MINUTE
HOUR
DAYOFWEEK
DAY
DAYOFYEAR
WEEK: Returns the week number of the date in the range [0, 53]. Weeks begin with Sunday, and dates prior to the first Sunday of the year are in week 0.
WEEK(<WEEKDAY>): Returns the week number of timestamp_expression in the range [0, 53]. Weeks begin on WEEKDAY. datetimes prior to the first WEEKDAY of the year are in week 0. Valid values for WEEKDAY are SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, and SATURDAY.
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.
MONTH
QUARTER
YEAR
ISOYEAR: Returns the ISO 8601 week-numbering year, which is the Gregorian calendar year containing the Thursday of the week to which date_expression belongs.
DATE
DATETIME
TIME

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.

How to print last sunday of the year in Oracle

I need to print the last sunday of the year from which adding 7 to it will give me all the sundays of next year.
I have the code to print all sundays for a particular year if i have a start date but i need the user to put the year so that last sunday of the previous year will be generated and 7 will be added to get first sunday of that year and so on till it reaches last sunday of next year
For example input year is 2017 it will check the last sunday of 2016 and add 7 to it to get first sunday of 2017 which is 1-1-2017 and it will go on printing all sundays till it reaches 31st december 2017
The function next_day() takes two arguments: a date and the name of a day of the week. It returns the closest "next" day (following the date argument) that matches the given day of the week. So the result is between one and seven days forward. (If you want 'Tuesday' and the input date is a Tuesday, the function returns the date seven days later.)
If you want the last Sunday of a year, it will be between Dec. 25 and Dec. 31. So if you call the next_day() function with the arguments Dec. 24 (!!) and 'Sunday' you'll get what you want.
The result will have the same time-of-day as the date argument, so if you give a date without a time-of-day, so will be the output (which is probably what you want). So:
select next_day(date '2016-12-24', 'Sunday') from dual;
NEXT_DAY(D
----------
2016-12-25
Added: If you take an input from your user, as a bind variable, you can do something like this:
select next_day(to_date(:input_year - 1 || '-12-24', 'yyyy-mm-dd'), 'Sunday') from dual;
If you provide 2017 as input (whatever mechanism your interface has for bind variables), the output will be 2016-12-25 (in DATE data type, so don't ask "in what format" - dates don't have a format!)

Oracle - How to get first Monday of the year?

How to get first Monday of the year?
select TRUNC(date'2015-01-01','YYYY')
,NEXT_DAY(TRUNC(date'2015-01-01','YEAR')+1,'MONDAY')
from dual;
01-JAN-2015 05-JAN-2015
To account for the possibility of the year starting on a Monday, you need to go back to the last day of the previous year, before going forward to the next Monday; for the current year:
next_day(trunc(sysdate, 'YYYY') - 1, 'Monday')
SQL Fiddle demo. This gives the first Monday of 2007 as January 1st; without the -1 adjustment it would say the 8th.
Try this:
select next_day(round(sysdate,'yyyy'),'mon')
from dual;

Get 1st Day of Week (Sunday)

I have this formula in my column to calculate the start date of a given week :
dateadd(week,[Week]-(1),
dateadd(day,(-1),
dateadd(week,
datediff(week,(0),
CONVERT([varchar](4),[Year],(0))+'-01-01'),
(1))))
Where Week and Year are other fields like 38 and 2012
Problem is, it calculates the start date of week 38/2012 as a monday (17th Sept), I would like it to be a sunday instead (16th Sept) is this possible?
Many thanks.
This will return you the first day of the week, given a week number and a year, assuming that the first day of the week is a Sunday.
Standard exclusions apply, e.g. don't try year 1499.
declare #tbl table ([Week] int, [Year] int)
insert #tbl select 38,2012
union all select 1,2012
union all select 0,2012
union all select 1,2013
select DATEADD(
Week,
[Week]-1,
DATEADD(
Day,
(8-##datefirst)-DATEPART(dw, CAST([Year]*10000+101 AS VARCHAR(8))),
CAST([Year]*10000+101 AS VARCHAR(8))))
from #TBL
Result
2012-09-16 00:00:00.000
2012-01-01 00:00:00.000
2011-12-25 00:00:00.000
2012-12-30 00:00:00.000
Note that the Week number starts from 1, and if the week doesn't start on a Sunday, then the first day of that week could end up in an earlier year (row #4). Because the Weeks are relative, you can use Week 0, -1 etc and it will still give you a result (row #3), rightly or wrongly.
You may also notice I used a different method to create a date out of the year, just as an alternative.
The (8-##datefirst) portion of the query makes it robust regardless of your DATEFIRST setting.
If you want the first day of the week to be Sunday you could change your database to make it so, using the DATEFIRST setting.
function getFirstDateOfThisWeek(d)
{
var TempDate = new Date(d || new Date());
TempDate.setDate(TempDate.getDate() + (#Config.WeekStartOn - 1 - TempDate.getDay() - 7) % 7);
return TempDate;
}
var StartDate = getFirstDateOfThisWeek(new Date()); //1st date of this week