How can I get a date using the week of the year in Oracle SQL?
I need to search for entries created after the beginning of the current week. Currently, I get the week of the year by doing select to_char(sysdate,'WW') from dual;, but then I can't do
select * from table where date > to_date(to_char(sysdate,'WW'), 'WW') because I get
ORA-01820: format code cannot appear in date input format
01820. 00000 - "format code cannot appear in date input format"
*Cause:
*Action:
You don't need to convert to a string and back, you can use truncate:
select * from table where date > trunc(sysdate,'WW')
Read more about the trunc() function and how the format model is applied.
Notice that WW gives you the same day as the first day of the year, so right now that would give 2020-09-02, which is a Wednesday - possibly not what you'd expect. It depends on your requirements of course, but you might want to work with IW which always starts from Monday, and would give 2020-09-07. If you have a different start day you can add or subtract a day, e.g. if your week starts on Sunday.
According to ORA-doc:
ORA-01820: format code cannot appear in date input format
Cause: A date specification contained an invalid format code. Only the following may > be specified when entering a date: year, month, day, hours, minutes, seconds, Julian day, > A.M./P.M. and B.C./A.D.
Action: Remove the invalid format code from the date specification.
You can't pass the weeknum to to_date() function. What you can do is e.g., the following
select * from table where date > (next_day(trunc(sysdate), 'SUNDAY') - 7)
Basically, next_day returns first date that meets specified weekday. Let's assume it's Monday 2020-09-07, next_day will return you the closest SUNDAY in the future, that is 2020-09-13, so you need to substract 7 to get date of the current week beginning. You can read more about it here
Related
I currently have a code that takes a date and returns a Sunday Start date. What I want is to get a Monday start date instead like the weekofyear() function.
Below is my current code where evt_time is my datetime variable:
date_sub(evt_time,pmod(datediff(to_date(evt_time),'1900-01-07'),7))
For instance, I would want 6/4/2018-6/10/2018 to be group into 6/4/2018.
Get the weekday with u argument and then use arithmetic to get the week start date as Monday.
select date_add(to_date(evt_time)
,1-cast(from_unixtime(unix_timestamp(to_date(evt_time),'yyyy-MM-dd'),'u') as int))
I'm trying to get the start of the week (Sundays, as a date) for a given date. This works except on Sundays since the day of the week origin begins on Monday:
SELECT DATE_SUB(FROM_UNIXTIME(UNIX_TIMESTAMP(CURRENT_DATE(), 'yyyy-MM-dd')), CAST(FROM_UNIXTIME(UNIX_TIMESTAMP(CURRENT_DATE(), 'yyyy-MM-dd'), 'u') AS INT))
The function above would return '2018-04-15' for a supplied date of '2018-04-22' whereas I want '2018-04-22'. Is the only recourse to write an case statement to offset for Sundays? I was hoping there was a nice parameter to FROM_UNIXTIME() that would have the weeks start on Sundays. I didn't find them in these docs:
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF
https://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
You could get the result with a simple trick without case statements.
Calculate the modulus value of the weekday with 7 and you should get your result.
SELECT DATE_SUB(CURRENT_DATE(), CAST(DATE_FORMAT(CURRENT_DATE(),'u')%7 AS INT));
I'm new to oracle sql . I want to fetch data between 2 dates .
Date is in this format in db : 13-DEC-10
This is the query I have written but its giving me error . How to proceed next
select sum(TOTAL_AMOUNT) from table a
where trn_date between
TO_DATE(01-APR-17, 'DD-MON-YYYY') AND TO_DATE(31-MAR-17, 'DD-MON-YYYY') ;
A date does not have a format - it is stored internally to the database as 7-bytes (representing year, month, day, hour, minute and second) and it is not until whatever user interface you are using (i.e. SQL/Plus, SQL Developer, Java, etc) tries to display it to you, the user, and converts it into something you would find meaningful (usually a string) that the date has a format.
To fix your query you just need to surround the date string in single quotes and to use YY to match the 2-digit year format (otherwise Oracle will assume that 17 in the format YYYY is the year 0017 and the century will not be as you expect):
select sum(TOTAL_AMOUNT)
from table a
where trn_date between TO_DATE('01-APR-17', 'DD-MON-YY')
AND TO_DATE('31-MAR-17', 'DD-MON-YY');
However, you can also use date literals (and skip having to match the date format model):
select sum(TOTAL_AMOUNT)
from table a
where trn_date between DATE '2017-04-01'
AND DATE '2017-05-31';
Alternatively you may use the year format of RR format against centurial problems, Don't forget to keep quotes for date values, and you may prefer calling sql with bind variables :
select sum(TOTAL_AMOUNT)
from table a
where trn_date between
TO_DATE('&date_1', 'DD-MON-RR') AND TO_DATE('&date_2', 'DD-MON-RR') ; -- where date_1 is 31-MAR-17 and date_2 is 01-APR-17, in your case.
What I mentioned by centurial problems :
The RR Datetime Format Element
The RR datetime format element is similar to the YY datetime format
element, but it provides additional flexibility for storing date
values in other centuries. The RR datetime format element lets you
store 20th century dates in the 21st century by specifying only the
last two digits of the year.
If you use the TO_DATE function with the YY datetime format element,
then the year returned always has the same first 2 digits as the
current year. If you use the RR datetime format element instead, then
the century of the return value varies according to the specified
two-digit year and the last two digits of the current year.
That is:
If the specified two-digit year is 00 to 49, then
If the last two digits of the current year are 00 to 49, then the
returned year has the same first two digits as the current year.
If the last two digits of the current year are 50 to 99, then the
first 2 digits of the returned year are 1 greater than the first 2
digits of the current year.
If the specified two-digit year is 50 to 99, then
If the last two digits of the current year are 00 to 49, then the
first 2 digits of the returned year are 1 less than the first 2 digits
of the current year.
If the last two digits of the current year are 50 to 99, then the
returned year has the same first two digits as the current year.
I was trying to get a date in oracle with today's date plus a provided time (hours and minutes)
The query was:
select TO_DATE ('02:03', 'hh24:mi') from dual
I was surprised by the result:
01/08/2017 02:03:00
It seems that the day is defaulted to the 1st of the month (I tried this on 3rd of the month) but the month and year are preserved.
Is that something expected or documented anywhere?
I think you can find the answer here
If you specify a date value without a date, then the default date is
the first day of the current month.
I need to find some records created in a range of quarters. For example, I'm looking for all records created between the 4th quarter of 2008 and the 1st quarter of 2010. I have this in my WHERE-clause:
...and r.record_create_date between to_date('2008 4','YYYY Q')
and to_date('2010 1','YYYY Q')
but Oracle says: ORA-01820: format code cannot appear in date input format. The Q is a valid date format symbol, so I'm not sure what's happened. Is this even a valid way to find values in between calender quarters, or is there a better way?
Also interesting, and possibly related, if I execute this:
select to_date('2009','YYYY') from dual;
The value displayed in my IDE is 2009-08-01. I would have expected 2009-08-04, since today is 2010-08-04.
This:
select to_date('2009 1','YYYY Q') from dual;
of course, fails.
(Oracle 10g)
Oracle says: ORA-01820: format code cannot appear in date input format. The Q is a valid date format symbol, so I'm not sure what's happened.
See the second column of table 2.15 at http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/sql_elements004.htm#i34948. Not all format elements are allowed when converting to dates, timestamps, etc.
I recommend against using between for date range checks. People often will miss values within the ending day that the expect to be included. So I would translate:
and r.record_create_date between to_date('2008 4','YYYY Q')
and to_date('2010 1','YYYY Q')
To
and to_date('2008-10-01', 'YYYY-MM-DD') <= r.record_create_date
and record_create_date < to_date('2010-04-01', 'YYYY-MM-DD') -- < beginning of 2Q2010.
Someone asked the same question on OTN: http://forums.oracle.com/forums/thread.jspa?threadID=1081398&tstart=255
The crux of the issue is that you can not specify "Q" in the TO_DATE function.
Given that you're already specifying a portion of the date, why not provide the entire date? Mind too that to_date('2010 1','YYYY Q') would give you Jan 1st, 2010 when you really want March 31st, 2010... at a second to midnight.
Since the relationship between quarters to months is one-to-many, it doesn't make sense to do TO_DATE('2008 1', 'yyyy q'); what date should be returned? The first of the quarter, the end of the quarter, ...? (On the other hand, converting a date to a quarter - like TO_CHAR(SYSDATE, 'yyyy q') makes sense because a specific date only exists in one quarter.)
So, if you do want a query that looks for a date that falls between two quarters, you will have to "rolll your own" (explicitly stating the dates of the start/end of a quarter.)
As a side note, in case anyone is considering not using TO_DATE please do not use things like: WHERE date_value BETWEEN 'date string1' and 'date string2' without the TO_DATE function. It assumes a default date format and under certain situations can avoid potentially useful indexes altogether.
Below is one example where the same query can have a different result.
select sysdate from dual where sysdate between '1-Jan-10' and '31-Dec-10';
SYSDATE
---------
04-AUG-10
SQL> alter session set nls_date_format = 'YYYY-MM-DD';
Session altered.
SQL> select * from dual where sysdate between '1-Jan-10' and '31-Dec-10';
no rows selected
(Notice that in the second instance no error is returned. It just assumes Jan 10, 0001 and Dec. 10th, 0031.)
I think the best way is to just input the quarter start date and quarter end dates without even bothering with to_date. I think if you use
between '1-Jan-10' and '31-Dec-10'
for example, then you don't (in Oracle I believe) need to_date and it isn't much more difficult than typing in the quarter number
To calculate in Oracle the first day of a quarter and the last day of a quarter from the year and quarter:
I Use the fact
start_month= -2 + 3 * quarter
last_month = 3 * quarter
variable v_year number
variable v_quarter number
exec :v_year :=2017
exec :v_quarter:=4
select :v_year as year,
:v_quarter as quarter,
to_date(:v_year||to_char(-2+3*:v_quarter,'fm00'),'yyyymm') as quarter_start,
last_day(to_date(:v_year||to_char(3*:v_quarter,'fm00')||'01 23:59:59','yyyymmdd hh24:mi:ss')) as quarter_end
from dual a;
YEAR|QUARTER|QUARTER_START |QUARTER_END
2017| 4|2017-10-01 00:00:00|2017-12-31 23:59:59