PLSQL - how to extract month and year only from full date - sql

I have a date like 01/03/2016. i want to get back 03/2016 in date type.
I know extract function, but it give me char type.
I don't want to use to_char.
Is there any way to do that?

Date datatype always has a day, month, year, hour, minute and second part.
You can use use to_char() function to extract the required component from a date.
select to_char(sysdate,'MM/YYYY') from dual;
However you can use below query but it will return 01-FEB-16
select to_date('01-2016','DD\YYYY') from dual;

Date does not have a format - it is represented internally by a series of bytes which you can see using:
SELECT DUMP( SYSDATE ) FROM DUAL;
Which outputs something like ( for the date 2016-02-17T09:13:44Z):
Typ=13 Len=8: 224,7,2,17,9,13,44,0
If you want the year & month then you can do use TRUNC( date_value, 'MM' ) or TO_CHAR( date_value, 'MM/YYYY' ):
SELECT TRUNC( SYSDATE, 'MM' ) AS "Date",
TO_CHAR( SYSDATE, 'MM/YYYY' ) AS monthyear,
DUMP( TRUNC( SYSDATE, 'MM' ) ) AS "Bytes"
FROM DUAL
Which outputs (note, the last 4 bytes are all zero after truncation):
Date | MonthYear | Bytes
--------------------------------------------------------------------
2016-02-01T00:00:00Z | 02/2016 | Typ-13 Len=8: 224,7,2,1,0,0,0,0
However, the output of the date is based on the NLS_DATE_FORMAT session parameter and your client will do an implicit TO_CHAR when it outputs the date using this format mask.
You can find out your current NLS_DATE_FORMAT with the query (as you can see above, mine is set to an ISO8601 format YYYY-MM-DD"T"HH24:MI:SS"Z"):
SELECT VALUE
FROM NLS_SESSION_PARAMETERS
WHERE PARAMETER = 'NLS_DATE_FORMAT';
You can then alter it using:
ALTER SESSION SET NLS_DATE_FORMAT = 'MM/YYYY';
Then when you do:
SELECT SYSDATE, DUMP( SYSDATE ) FROM DUAL;
You will get the output:
Date | Bytes
-----------------------------------------------
02/2016 | Typ=13 Len=8: 224,7,2,17,9,13,44,0
Note, the last 4 bytes are not all non-zero (the date has not been truncated) but now the output is just the month/year.
However, it is just simpler to store the date as a date (with the day and time components unchanged) and then use TO_CHAR( date_value, 'MM/YYYY' ) whenever you want to output it as you will get the output format you want without changing the value across the entire session.

Related

How to pass timestamp value in Oracle Stored Procedure?

I have a table column which has timestamp data type. How to pass timestamp value to the table column? I am passing to_timestamp('1240','HH:MI:SS') in oracle procedure. In DB table I have a value like 01-AUG-20 12.40.00.000000000 PM . I only want to store timestamp in the DB table. Is there a way? Please guide me on this. Thanks
You appear to be confused about what the values store. A TIMESTAMP data type stores a date and time with year, month, day, hour, minute, second and optional fractional seconds and time zone components; you cannot have a TIMESTAMP with just hour, minute and second components as it will always have year-day components.
If you want to store time then either:
Use an INTERVAL DAY TO SECOND data type (with zero days);
Use a DATE (or, if you want fractional seconds, TIMESTAMP) data type and set the year-day components to a fixed value (or ignore them);
Use a string in a fixed format; or
Store the number of seconds after midnight and use TO_DATE( value, 'SSSSS' ) to convert to a date and then TO_CHAR to format it as needed.
I would say that if you want to add times then use an INTERVAL data type as it will natively support that.
For example:
CREATE TABLE times1 ( value INTERVAL DAY TO SECOND );
INSERT INTO times1 ( value ) VALUES ( INTERVAL '12:40' HOUR TO MINUTE );
SELECT * FROM times1;
Which outputs:
| VALUE |
| :------------------ |
| +00 12:40:00.000000 |
If you want to display times then use a DATE and ignore the year-to-day components as you can easily format the time using TO_CHAR.
For example:
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';
CREATE TABLE times2 ( value DATE );
INSERT INTO times2 ( value )
-- Fixed date
SELECT DATE '1970-01-01' + INTERVAL '12:40' HOUR TO MINUTE FROM DUAL UNION ALL
-- Today's date
SELECT TRUNC( SYSDATE ) + INTERVAL '12:40' HOUR TO MINUTE FROM DUAL UNION ALL
-- First of current month
SELECT TO_DATE( '12:40', 'HH24:MI' ) FROM DUAL;
SELECT value, TO_CHAR( value, 'HH24:MI' ) FROM times2;
Which outputs:
VALUE | TO_CHAR(VALUE,'HH24:MI')
:------------------ | :-----------------------
1970-01-01 12:40:00 | 12:40
2020-08-05 12:40:00 | 12:40
2020-08-01 12:40:00 | 12:40
db<>fiddle here

Concatenating and comparing values of fields as date

Can you help me out with this problem.
I have the following fields below with sample values:
STRM = 1171
TERM_BEGIN_DT = 01-SEPT-18
TERM_END_DT = 31-JUL-19
ACAD_YEAR = 2018
*Additional Info:
2018/19 Academic Year
1st August 2018 – 31st July 2019*
What I want to do is, I want to get the STRM within the current ACADEMIC YEAR
The SQL i want is:
SELECT STRM FROM PS_TERM_TBL
WHERE TERM_BEGIN_DT BETWEEN '01-AUG-18' AND '31-JUL-19';
The problem is, given only the values above, I have to hard code '01-AUG-' and '31-JUL-' and concatenate each with the '18' and '18' + 1 of ACAD_YEAR respectively.
Main question is, how do i do this?
How do i get the 18 of 2018 in ACAD_YEAR and then add 1 to it to get 19?
I think i will get a invalid type error with this one, so what do i have to convert to to_date in order for the comparison to be legit?
You can use ADD_MONTHS to translate the epoch date of the start of the current academic year back to the start of the calendar year, TRUNCate the value to the beginning of the year, and then use ADD_MONTHS again to reverse the initial translation:
SELECT STRM
FROM PS_TERM_TBL
WHERE TERM_BEGIN_DT >= ADD_MONTHS( TRUNC( ADD_MONTHS( SYSDATE, -7 ), 'YYYY' ), 7 )
AND TERM_BEGIN_DT < ADD_MONTHS( TRUNC( ADD_MONTHS( SYSDATE, -7 ), 'YYYY' ), 19 )
As an aside, '01-AUG-18' is not a date - it is a string literal that Oracle is implicitly converting to a date using the NLS_DATE_FORMAT session parameter (which is something that can change depending on the user's territory and users can also change their own session's settings so should not be relied upon to be give a consistent format model). If you want to specify dates then you should use either:
a date literal DATE '2018-08-01'; or
an explicit conversion from a string literal TO_DATE( '01-AUG-18', 'DD-MON-RR', 'NLS_DATE_LANGUAGE = American' )

oracle compare a date with the current date

I have to convert a column to a date and then compare the month of the column with the current month.
The column looks like this :
Date
0117
0217
0317
..
I know how to convert it but cant compare it.
select date,to_date(date, 'mmyy')
from table
where ????
any ideas?
You can convert the value to a date using to_date():
select to_date(mmyy, 'MMYY')
from t;
Note that I renamed the column mmyy to clarify what it contains.
This returns the first day of the month.
The result of to_date() can then be compared to the current date. For instance, to match the first of date of the month:
where to_date(mmyy, 'MMYY') = trunc(sysdate)
If you want to match everything in the month, just use an appropriate comparison:
where to_char(to_date(mmyy, 'MMYY'), 'YYYY-MM') = to_char(sysdate, 'YYYY-MM')
or, more simply:
where mmyy = to_char(sysdate, 'MMYY')
You can convert the current date to a string and use string comparisons (which would allow you to use an index on your column):
SELECT *
FROM your_table
WHERE your_date_column = TO_CHAR( SYSDATE, 'MMYY' )
or you can convert the column to a date and compare it (which would not use an index on your column but could use a function-based index, if you created one):
SELECT *
FROM your_table
WHERE TO_DATE( your_date_column, 'MMYY' ) = TRUNC( SYSDATE, 'MM' )

When and why does the TRUNC(DATE, [FORMAT]) used in the real world

I am getting into Oracle database. I came across the TRUNC(DATE, [FMT]) function. I am not really clear on it except it seems to return the beginning value of some sort?
Can somebody educate me on it? When or what would it be used for at work, or why somebody might want to use the function?
Try this query to know when it might be usefull:
ALTER SESSION SET NLS_DATE_FORMAT = 'yyyy-mm-dd hh24:mi:ss';
select sysdate,
trunc( sysdate, 'mi' ) As beginning_of_current_minute,
trunc( sysdate, 'mi' ) As beginning_of_current_hour,
trunc( sysdate, 'dd' ) As beginning_of_current_day,
trunc( sysdate, 'iw' ) As beginning_of_current_week,
trunc( sysdate, 'mm' ) As beginning_of_current_month,
trunc( sysdate, 'q' ) As beginning_of_current_Quarter,
trunc( sysdate, 'y' ) As beginning_of_current_Year
FROM dual;
An example - you want to get all orders starting from the beginning of the current week:
SELECT *
FROM ORDERS
WHERE order_date >= trunc( sysdate, 'iw' )
A real world example would be if you wanted to aggregate results from a table by year. You could use the TRUNC function like this:
SELECT TRUNC(my_date, 'YEAR') the_year, count(*)
FROM some_table
GROUP BY TRUNC(my_date, 'YEAR');
...which would return a set of results with the first column the date truncated to the beginning of the year and the second column a count of all the records with dates within that year.
the_year, count(*)
_________________
01-JAN-12, 543
01-JAN-13, 1268
01-JAN-14, 1134
01-JAN-15, 1765
There are obviously other ways to achieve the same thing, but this is a real world example of how you might use TRUNC.
Another might be if you are comparing dates and you only want to use a certain degree of precision. If you have a timestamp column and you want all the records for today, you could select based on a range where the timestamp is greater than midnight yesterday and less than midnight today, or you could select where the timestamp, truncated to the DATE, is equal to today.
https://docs.oracle.com/cd/E29805_01/server.230/es_eql/src/cdfp_analytics_lang_trunc.html
Another thing it is useful for is to get the time component of the current day. I use an expression like this all the time:
SELECT sysdate - trunc(sysdate) AS TodaysTime FROM DUAL
Because the system date is stored in a decimal format (e.g. sysdate = 42651.2426897456) and the integer value corresponds to midnight, I can use the above statement to get only the decimal portion (e.g. TodaysTime = 0.2426897456, or just before 6 AM).
There may be easier ways to do this, but in my applications this has been the easiest as I frequently need to work with only the day's time component.

Oracle SQL WHERE MONTH = N

In my select I am using this
(TRUNC(TO_DATE(TIMESTAMP, 'dd.mm.yyyyHH24:mi'))) TIMESTAMP,
to get the following output in a date format: e.g. 22/04/2016
Now I want to add a statement in my WHERE-clause to show only dates in special months, for example only dates which are in MARCH and APRIL
I tried using this:
WHERE (TRUNC(TO_DATE(TIMESTAMP, 'mm'))) in (3,4)
which gives me an error.
Thanks for helping.
Just use EXTRACT() on the timestamp:
WHERE EXTRACT(MONTH FROM timestamp) IN (3, 4)
This would match records from March and April.
In my select I am using this
(TRUNC(TO_DATE(TIMESTAMP, 'dd.mm.yyyyHH24:mi'))) TIMESTAMP,
to get the following output in a date format: e.g. 22/04/2016
TO_DATE takes a string value so your "TIMESTAMP" column will be implicitly converted to a string and then back to a date... which is unnecessary (and relies on the value of the NLS_TIMESTAMP_FORMAT session parameter to format the implicit conversion - which, if changed, will break the query); you can just do:
TRUNC( "TIMESTAMP" ) AS "TIMESTAMP"
If you want to then filter on different months then you can do (as suggested by Tim Biegeleisen):
WHERE EXTRACT( MONTH FROM "TIMESTAMP" ) IN ( 3, 4 )
or if you want a particular year then
WHERE TRUNC( "TIMESTAMP", 'MM' ) IN ( DATE '2016-03-01', DATE '2016-04-01' )
or, so you can use an index on the column:
WHERE "TIMESTAMP" >= DATE '2016-03-01'
AND "TIMESTAMP" < DATE '2016-05-01'