Trying to convert datetime in date in oracle - sql

Hi i'm trying to convert date 01-03-2020 10:48:27 which obtained from query
SELECT
LAST_DAY( ADD_MONTHS(SYSDATE,-3 ) )+1
FROM
dual;
into '01-Mar-2020' but not able to do trying many concept
eg.
trunc(SELECT LAST_DAY( ADD_MONTHS(SYSDATE , - 3 ) )+1 FROM dual),'YEAR')
and
SELECT TRUNC(TO_DATE('SELECT LAST_DAY( ADD_MONTHS(SYSDATE , - 3 ) )+1 FROM dual','DD-MON-YY'), 'YEAR') "New Year" FROM DUAL;
but getting error
Any idea would be appreciated

You're making things way too complicated. Oracle TRUNC takes an additional parameter to specify whatever time interval to truncate to:
SELECT TRUNC(some_date_here, 'MON') FROM dual
If you put some_date_here as sysdate, then currently it will return 01-May-2020 until next month when it starts returning 01-Jun-2020
You can truncate to any interval; TRUNC 01/01/2000 12:34:56 with 'MI' will return 01/01/2000 12:34:00. Truncating to DD is the default (cut the time off). Truncating to DAY sets the date back to the day that started the week in the country oracle thinks it is in (probably a Sunday or Monday)
More info: https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions230.htm#i1002084
As I understood your problem you want to go from the current date, to the first of the month that was between 2 and < 3 months ago (so if it's May now, you want to go back to first of March until it's June, when you want to go back to first of April)
If you hence, in the current date of 5th May, want to go back to a date of 1 March, take 2 months off the current date and then TRUNC to the start of the month:
SELECT TRUNC(ADD_MONTHS(sysdate, -2), 'MON') FROM dual
Don't forget you can TRUNC to the nearest quarter of a year, so if you're doing a report that is "the current quarter", then looking at a variation of TRUNC(sysdate, 'Q') would be the way to go
Lastly, I'd urge you NOT to use oracle to convert your dates to strings (in most cases) - if you keep it as a date all the way 'tIl it hits the user's computer it can be formatted for their regional preferences. If you make a decision as to the format as its coming out the dB it makes it much harder to deliver a good international experience for your app

"Convert" in your case means TO_CHAR; alter session is here to set default format for this session.
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';
Session altered.
SQL> select
2 last_Day(add_months(sysdate, -3)) + 1 orig,
3 to_char(last_day(add_months(sysdate, -3)) + 1, 'dd-Mon-yyyy', 'nls_Date_language = english') result
4 from dual;
ORIG RESULT
------------------- --------------------
01.03.2020 07:25:44 01-Mar-2020
SQL>
Or, if you altered the session, you'd get it as
SQL> alter session set nls_date_language = 'english';
Session altered.
SQL> alter session set nls_date_format = 'dd-Mon-yyyy';
Session altered.
SQL> select
2 last_Day(add_months(sysdate, -3)) + 1 orig
3 from dual;
ORIG
-----------
01-Mar-2020
SQL>
But, yes - usually we TO_CHAR it.

Related

Week start from Sunday while calculating weekday

I am trying to find the weekday for Sunday to Saturday. In oracle by default Monday is the first day of the week. So When I calculate weekday with following query
Select to_char(sysdate, 'D') from dual
as today is 09/12/2022 this is giving me result as 5 as week start from Monday. I want this should be calculated as week start from Sunday. Ideally, answer should be 6 if this week start from Sunday.
Is there any easy way to do it, I can use case statement, but that is not a good way. Please help.
Talk to your DBA to fix territory. If it was set to e.g. India, then you wouldn't have to calculate anything:
SQL> alter session set nls_territory = 'India';
Session altered.
SQL> Select to_char(sysdate, 'D') from dual;
T
-
6
SQL>
In Oracle, the first day of a week is determined by NLS_TERRITORY parameter. So use a value of NLS_TERRITORY where Sunday is the first weekday, for example, AMERICA.
alter session set nls_territory=RUSSIA
select to_char(sysdate, 'D')
from dual
TO_CHAR(SYSDATE,'D')
5
alter session set nls_territory=AMERICA
select to_char(sysdate, 'D')
from dual
TO_CHAR(SYSDATE,'D')
6
fiddle
Option 1: NLS_TERRITORY session parameter
In Oracle, the day of the week depends on the NLS_TERRITORY session setting:
SELECT TO_CHAR(DATE '2022-12-11', 'D') AS day, -- a sunday
(SELECT value FROM NLS_SESSION_PARAMETERS WHERE parameter = 'NLS_TERRITORY')
AS territory
FROM DUAL;
Outputs different values for different parameters. I.e., if you use:
ALTER SESSION SET NLS_TERRITORY='America';
ALTER SESSION SET NLS_TERRITORY='Germany';
ALTER SESSION SET NLS_TERRITORY='India';
ALTER SESSION SET NLS_TERRITORY='Oman';
ALTER SESSION SET NLS_TERRITORY='Bangladesh';
and run the query for each then the outputs are:
DAY
TERRITORY
1
AMERICA
7
GERMANY
1
INDIA
2
OMAN
3
BANGLADESH
So you could just pick the correct territory for your database, i.e.:
ALTER SESSION SET NLS_TERRITORY='India';
Option 2: Compare to the start of the ISO-week
Or if you want to be independent of the session settings then you can compare it to the start of the ISO-week (which is always midnight Monday) and offset by one day to change the comparison from Monday-Sunday to Sunday-Saturday:
SELECT TRUNC(SYSDATE + 1) - TRUNC(SYSDATE + 1, 'IW') + 1 AS day
FROM DUAL;
Which, for today (Friday) outputs:
DAY
6
fiddle
I found the answer to this, which is dead easy
select mod(to_char(sysdate,'D'),7)+1 as Weekday from Dual

How in Oracle to calculate difference between current date and column date?

I have column INACTIVE_TIME where I need to put integer number (how many days pass from some date), to represent difference between current date and column date ("LOAD_DATE" column).
In column LOAD_DATE I have data in format 03-AUG-22 03.55.57.587481000 PM.
I understand I need to get current date and than minus date from LOAD_DATE column.
I try something like this:
SELECT COUNT(*)
FROM TABLE_NAME
WHERE ((TO_DATE(SYSDATE,'DD/MM/YYYY')-(TO_DATE(LOAD_DATE,'DD/MM/YYYY'));
It is about load_date column's datatype, not the way you see that value (because it can be changed). I presume (and hope) it is timestamp; you aren't storing it as a string, are you?
If so, then you don't apply to_date to sysdate - it is a function that already returns date datatype.
Setting timestamp and date format (just to know what is what; your tool displays different format, with month name and two-digits year) (you don't have to do that).
SQL> alter session set nls_timestamp_format = 'dd.mm.yyyy hh24:mi:ss.ff9';
Session altered.
SQL> alter session set nls_date_format = 'dd.mm.yyyy hh24:mi:ss';
Session altered.
Sample table; note datatype:
SQL> create table table_name (load_date timestamp);
Table created.
SQL> insert into table_name values (systimestamp);
1 row created.
Query you're looking for (at least, I think so):
SQL> select load_date, sysdate,
2 --
3 sysdate - load_date as diff
4 from table_name;
LOAD_DATE SYSDATE DIFF
------------------------------ ------------------- ------------------------------
04.08.2022 10:22:58.101062000 04.08.2022 10:23:08 +000000000 00:00:09.898938
SQL>
To extract days, hours, minutes ... whatever, you can use that function - extract. For example:
SQL> select load_date,
2 sysdate,
3 sysdate - load_date as diff,
4 --
5 extract (day from sysdate - load_date) as diff_days,
6 extract (hour from sysdate - load_date) as diff_hours,
7 extract (minute from sysdate - load_date) as diff_minutes
8 from table_name;
LOAD_DATE SYSDATE DIFF DIFF_DAYS DIFF_HOURS DIFF_MINUTES
------------------------- ------------------- -------------------------- ---------- ---------- ------------
04.08.22 10:22:58,101062 04.08.2022 11:51:32 +000000000 01:28:33.898938 0 1 28
SQL>
Your Where clause isn't saying anything. What are you wanting it to filter?
Try
Where (sysdate - table_name.load_date) > 0
This might not be what you want, but you need to tell the query something else

Oracle's ( or not) weekday convention

I have written a query for my co-workers to use, that involves pulling data from Oracle Express g11 on a given date.
The date that query uses is last weekday(yesterday or Friday).
For some reason same query returns different number to represent the day of the week.
Example:
SELECT TRUNC('13June2016') - TRUNC('13June2016', 'D')
FROM DUAL
When run on my computer this query returns 0 but on my co-worker's computer it returns 1. This happens on every SQL client/interface available to us.
To the best of my knowledge our computers and users in DB are setup the same but clearly some setting is off.
Frankly I tried to google where does this discrepancy comes from but I received a lot of unrelated results. I'm lost because I'd don't even know where to look for the setting(or bug not sure) that accounts for this difference.
The D format modifier relies on the session's NLS settings:
alter session set nls_territory = 'America';
alter session set nls_date_format = 'YYYY-MM-DD';
select to_char(date '2016-06-13', 'D') char_d,
trunc(date '2016-06-13', 'D') trunc_d,
date '2016-06-13' - trunc(date '2016-06-13', 'D') diff1,
trunc(sysdate) - trunc(sysdate, 'D') diff2
from dual;
C TRUNC_D DIFF1 DIFF2
- ---------- ---------- ----------
2 2016-06-12 1 1
alter session set nls_territory = 'United Kingdom';
alter session set nls_date_format = 'YYYY-MM-DD';
select to_char(date '2016-06-13', 'D') char_d,
trunc(date '2016-06-13', 'D') trunc_d,
date '2016-06-13' - trunc(date '2016-06-13', 'D') diff1,
trunc(sysdate) - trunc(sysdate, 'D') diff2
from dual;
C TRUNC_D DIFF1 DIFF2
- ---------- ---------- ----------
1 2016-06-13 0 0
(Interestingly in producing that I stumbled over bug 14073795 when using trunc(date '2016-06-13'); the trunc is redundant and it seems quite inconsistent - changing a column alias can make it appear or disappear - so I don't think it's relevant to what you're seeing).
So it seems that you and your colleague have your PCs in different locales, and the clients you tested in either inherited the locale or explicitly set the territory differently.
To get consistent results regardless of the locale/NLS settings you can use the 'IW' format element instead of 'D', as that gives:
Same day of the week as the first day of the calendar week as defined by the ISO 8601 standard, which is Monday
alter session set nls_territory = 'America';
alter session set nls_date_format = 'YYYY-MM-DD';
select to_char(date '2016-06-13', 'IW') char_iw,
trunc(date '2016-06-13', 'IW') trunc_iw,
date '2016-06-13' - trunc(date '2016-06-13', 'IW') diff1,
trunc(sysdate) - trunc(sysdate, 'IW') diff2
from dual;
CH TRUNC_IW DIFF1 DIFF2
-- ---------- ---------- ----------
24 2016-06-13 0 0
alter session set nls_territory = 'United Kingdom';
alter session set nls_date_format = 'YYYY-MM-DD';
select to_char(date '2016-06-13', 'IW') char_iw,
trunc(date '2016-06-13', 'IW') trunc_iw,
date '2016-06-13' - trunc(date '2016-06-13', 'IW') diff1,
trunc(sysdate) - trunc(sysdate, 'IW') diff2
from dual;
CH TRUNC_IW DIFF1 DIFF2
-- ---------- ---------- ----------
24 2016-06-13 0 0
You can read more about how the format models are used in trunc() and round() functions, and more generally about date format models.
Relying on implicit conversion is also not a good idea; TRUNC('13June2016', 'D') is implicitly converting the string '13June2016' to a date using your session's NLS_DATE_FORMAT setting. Running that in a session with a different setting will error. And TRUNC('13June2016') is redundant as the implicitly-converted date will already have its time set to midnight, if it doesn't error.
You should always either explicitly convert the string and specify the format model, e.g. TRUNC(TO_DATE('13June2016', 'DDMonthYYYY', 'NLS_DATE_LANGUAGE=ENGLISH'), 'D') (where the third argument is needed in case the session date language is something else, which would stop June being recognised; or more simply use an ISO date literal like DATE '2016-06-13'. You may be using a datetime variable in your real code of course.

Oracle SQL What does start_date-1 mean?

Oracle SQL What does start_date-1 mean?
Is it just one day less the start_date?
Assuming your datatype is a date or timestamp, yes, it will remove a full day from your date:
SELECT SYSDATE AS "start_date",
SYSDATE - 1 AS "start_date -1"
FROM DUAL;
Returns
26/08/2015 11:09:21 | 25/08/2015 11:09:21
YES. It will subrtract 1 day from the start_date.
Given that the data type of start_date is DATE or TIMESTAMP, subtracting N from it would subtract N number of days.
For example,
SQL> alter session set nls_date_format='DD-MM-YYYY HH24:MI:SS';
Session altered.
SQL> SELECT sysdate, sysdate -1 FROM DUAL;
SYSDATE SYSDATE-1
------------------- -------------------
26-08-2015 14:45:35 25-08-2015 14:45:35
SQL>
Remember, date has both date and time elements, so you will go back to previous day with exactly that time portion.
Yes it is 1 day earlier to start_date.

Oracle DB select between dates

I would like to query number of records between night 12.01 AM to 11.59 PM but issue is, I would like to schedule this query so I cant specify any hard coded dates.
Query should pull number of records for query date between 12.01 AM to 11.59 PM.
Could someone please help me on this.
Query should pull number of records for query date between 12.01 AM to 11.59 PM.
You could do it as:
TRUNC gives you date element truncating the time portion
convert the SYSDATE into string using TO_CHAR
then concatenate the time element
finally convert everything back to DATE
SYSDATE returns the current date and time set for the operating system on which the database resides. The datatype of the returned value is DATE, and the format returned depends on the value of the NLS_DATE_FORMAT initialization parameter.
So, you don't have to hard-code any DATE value if you want to execute the query everyday.
Use the following in the filter predicate:
BETWEEN
TO_DATE(TO_CHAR(TRUNC(SYSDATE), 'MM/DD/YYYY') ||' 00:01', 'MM/DD/YYYY HH24:MI')
AND
TO_DATE(TO_CHAR(TRUNC(SYSDATE), 'MM/DD/YYYY') ||' 23:59', 'MM/DD/YYYY HH24:MI')
Demo
SQL> alter session set nls_date_format = 'MM/DD/YYYY HH24:MI:SS';
Session altered.
SQL> SELECT to_date(TO_CHAR(TRUNC(SYSDATE), 'MM/DD/YYYY')
2 ||' 00:01', 'MM/DD/YYYY HH24:MI') start_dt ,
3 to_date(TO_CHAR(TRUNC(SYSDATE), 'MM/DD/YYYY')
4 ||' 23:59', 'MM/DD/YYYY HH24:MI') end_date
5 FROM dual;
START_DT END_DATE
------------------- -------------------
05/06/2015 00:01:00 05/06/2015 23:59:00
SQL>
So, you don't have to put any hard-coded value for current date, the SYSDATE will take care of it. All you are doing is:
TRUNC gives the date element by truncating the time portion.
Then concatenating the required time element
Converting the entire string into DATE using TO_DATE
I would like to schedule this query so I cant specify any hardcord dates
To schedule the query to execute everyday, you could use DBMS_SCHEDULER.
I'm going to assume you want everything that happens during the date of interest. So you want everything from and including midnight of that day and before midnight of the next day.
declare
AsOf Date = date '2015-01-01 13:14:15';
select ...
from tablename
where tabledate >= trunc( AsOf )
and tabledate < trunc( AsOf ) + 1;
If you know the date doesn't have a time portion, just can eliminate the calls to trunc. But you may want to keep them just in case.