Last date with time of the month - sql

Need your help to conclude the query to fetch last date time of the sysdate month.
select to_char(last_day(sysdate),'DD-Mon-YYYY HH24:MI:SS') from dual
it gives last date as expected, but I need time as 23:59:00 which is not possible thru above query.

You could use TRUNC on next day i.e. SYSDATE + 1, and then subtract 60 seconds i.e. 60/86400 to get the desired output.
SQL> SELECT to_char((trunc(last_day(sysdate)) +1) - 60/86400,'DD-Mon-YYYY HH24:MI:SS') dt
2 FROM dual;
DT
--------------------
29-Feb-2016 23:59:00
SQL>
You could also use interval '1' minute or interval '60' second instead of 60/86400.

If you just want it for display for some reason you can hard-code the time into the format mask:
select to_char(last_day(sysdate), 'DD-Mon-YYYY "23:59:00"') from dual;
But you probably really want it as a date object, in which case you can add 23 hours and 59 minutes to the truncated (midnight) date, wchi is 1439 of the 1440 minutes in a day:
select to_char(trunc(last_day(sysdate)) + 1439/1440, 'DD-Mon-YYYY HH24:MI:SS')
from dual;
Or you can go to the next day and remove a minute, either with fractional days or with intervals:
select to_char(trunc(last_day(sysdate)) + interval '1' day - interval '1' minute,
'DD-Mon-YYYY HH24:MI:SS') from dual;
Generally if you're working with time periods you want to include up to 23:59:59, which you can also do with any of those methods, but as Damien_The_Unbeliever said in a comment, it's easier to compare against the start of the next period (e.g. < add_months(trunc(sysdate, 'MM'), 1). It's easy to accidentally miss part of a day by not taking the time into account properly, particularly if you actually have a timestamp rather than a date.

Related

select difference of two dates in hours and minutes

i have the following problem,
i am trying to find the difference of two dates in hours and minutes, for example
select to_date('13.05.2021 09:30','DD.MM.YYYY HH24:MI')
- to_date('13.05.2021 08:15','DD.MM.YYYY HH24:MI') from dual;
obiously it returns the difference in days, so the output will be 0,
i am expecting somthing like 01:15
Depending on the data type you need for your result...
If an interval day to second will work, then you can do this:
select (date2 - date1) * interval '1' day from dual;
For example:
select (to_date('13.05.2021 09:30','DD.MM.YYYY HH24:MI')
- to_date('13.05.2021 08:15','DD.MM.YYYY HH24:MI'))
* interval '1' day as diff
from dual;
DIFF
-------------------
+00 01:15:00.000000
Give this a try; if you need a different data type for the result, let us know. Note that, stupidly, Oracle doesn't support aggregate functions for intervals; so if you need a sum of such differences, you should apply the aggregation first, and only use this trick to convert to an interval as the last step.
In addition to #mathguy answer in case you need a specific output format:
TO_CHAR does not work with INTERVAL values. Either use EXTRACT
EXTRACT(HOUR FROM ((date2 - date1) DAY TO SECOND)) ||':'|| EXTRACT(MINUTE FROM ((date2 - date1) DAY TO SECOND))
or REGEXP_SUBSTR
REGEXP_SUBSTR((date2 - date1) DAY TO SECOND, ' \d{2}:\d{2}')
You may need some fine-tuning for proper output.

Select rows within last complete minute

I want to find rows in my database which have a timestamp within the last complete minute.
For example:
When it is 12:02:43 --> from 12:01:00 to 12:01:59 (inclusive)
When it is 14:01:00 --> from 14:00:00 to 14:00:59 (inclusive)
When it is 16:24:59 --> from 16:23:00 to 16:23:59 (inclusive)
I found the following statement.
select *
from table
where time < to_date(to_char(sysdate, 'DD.MM.YYYY HH24:MI'), 'DD.MM.YYYY HH24:MI')
and time >= to_date(to_char(sysdate - numtodsinterval(1, 'Minute'), 'DD.MM.YYYY HH24:MI'), 'DD.MM.YYYY HH24:MI')
The statement works, but converting the date to a string and then back to a date seems a little weird. Is there any other method to use only minutes as precision (without seconds)?
Oracle-specific functions could be used, but I'd prefer a standard SQL way.
You can use TRUNC(SYSDATE,'MI') -> TRUNC('12:02:43','MI') = 12:02.
Or you can use this select extract(MINUTE from current_timestamp) from dual;
You can truncate timestamps (and dates) to the nearest minute - so you can use TRUNC( SYSTIMESTAMP, 'MI' ) to round to the start of the current minute and subtract INTERVAL '1' MINUTE to get the start of the previous minute:
select *
from table_name
where time >= TRUNC( SYSTIMESTAMP, 'MI' ) - INTERVAL '1' MINUTE
and time < TRUNC( SYSTIMESTAMP, 'MI' )
You are right, converting it to string an back seems unnecessary. I'd leave it as a date. How about:
SELECT *
FROM t
WHERE t BETWEEN TRUNC(SYSDATE,'MI')
AND TRUNC(SYSDATE,'MI')+1/24/60/60*59;
TRUNC(...,'MI') chops of the seconds, for instance
SELECT trunc(sysdate,'MI'), TRUNC(SYSDATE,'MI')+1/24/60/60*59 from dual;
returns
2018-06-06 11:04:00 2018-06-06 11:04:59
EDIT: As David Faber pointed out, this works only if your column has the datatype DATE. For the datatype TIMESTAMP, you're better of with #MT0's solution.

Select data between timestamps

Usecase: Query to select the records for a whole day and it should run regularly.
This is my query.
Select to_char(in_date + interval '12' hour, 'DD-MON-YYYY HH24:MI:SS')
from my_table
where incoming_date > sysdate-2 and incoming_date < sysdate
I need to select yesterday's data only. Because of the conversion in the select statement I got today's data also. How do I select only yesterday's data? My DB is in UTC+7.00 standard. I need to display it in local standard so that I did a conversion in select statement. And how do I display only yesterday's data?
I'm stuck. Please help me
To get all data from yesterday you should use
SELECT TO_CHAR(IN_DATE + INTERVAL '12' HOUR, 'DD-MON-YYYY HH24:MI:SS')
FROM MY_TABLE
WHERE INCOMING_DATE BETWEEN TRUNC(SYSDATE) - INTERVAL '1' DAY
AND TRUNC(SYSDATE) - INTERVAL '1' SECOND
If, for example, SYSDATE is 05-NOV-2017 18:56:35, the time interval used in the BETWEEN comparison will be from 04-NOV-2017 00:00:00 to 04-NOV-2017 23:59:59. BETWEEN comparisons are inclusive of both endpoints so this will only return data with an INCOMING_DATE of sometime on 04-NOV-2017, in this example.
Best of luck.
only to get the
yesterday's data
make your
WHERE condition as
incoming_date between trunc(sysdate) - interval '1' day and trunc(sysdate) - interval '1' second
My DB is in UTC+7.00 standard. I need to display it in local standard so that I did a conversion in select statement.
Using a magic value (INTERVAL '12' HOUR) does not describe what it means or the assumptions you made when chosing that value. Instead you can better describe the process by using FROM_TS( timestampvalue, timezonestring ) to convert the value from a TIMESTAMP to a TIMESTAMP WITH TIME ZONE data type and then use AT LOCAL TIME to convert it to the local time. Then if you have daylight savings time or port the query to another international location then it will still display in the current local time. Like this:
SELECT TO_CHAR(
FROM_TZ( CAST( in_date AS TIMESTAMP ), '+07:00' ) AT LOCAL TIME,
'DD-MON-YYYY HH24:MI:SS'
)
FROM my_table
WHERE incoming_date >= TRUNC( SYSDATE ) - INTERVAL '1' DAY
AND incoming_date < TRUNC( SYSDATE )
And how do I display only yesterday's data?
TRUNC( SYSDATE ) will truncate today's date back to midnight. To get yesterday's data then you can get values that are greater or equal to TRUNC( SYSDATE ) - INTERVAL '1' DAY (one day before midnight today) and also less than TRUNC( SYSDATE ) (midnight today).
I'm not exactly sure I get your question, but I think I can explain some stuff.
I'll be assuming your table is a bit like this:
date_added | some_data | some_more_data
------------|-----------|----------------
date | data1 | data2
As I understand your goal is to fetch all the rows that were added to a table the day before the query is run using a select statement. but your current attempt fails at doing so by also returning today's results.
Here is what's happening (I think):
SYSDATE doesn't just give you the current date, it also gives you the time. You can see that for your self by simply altering your current session and setting the date/time format to one that includes both time and date
ALTER SESSION SET NLS_DATE_FORMAT = 'DD-MON-YYYY HH24:MI:SS';
The reason why you would be getting today's rows is simple, your query is asking for all the rows who's date_added field is between right now and right now - 24 hours. Not today and today - 24 hours.
So what is the solution?
Use the TRUNC function to trim the SYSDATE to the day instead!
https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions201.htm
SELECT
T.*
FROM
MY_TABLE T
WHERE
T.DATE_ADDED BETWEEN (TRUNC(SYSDATE,'day') - 1) AND TRUNC(SYSDATE,'day');
As you did mention timezones being a thing keep in mind that SYSDATE returns the date on the server itself and not your computer's.
More on that here: https://stackoverflow.com/a/17925834/7655979
Usually I compare the date only using Trunc.
WHERE trunc(incoming_date) = trunc(sysdate-1)

How to subtract hours from a date in Oracle so it affects the day also

I'm trying to subtract date from Oracle so it even effect the day as well. For example, if
the timestamp is 01/June/2015 00 hours and if I subtract 2 hours, I want to be able to go to to 31/May/2014 22 hours.
I tried
to_char(sysdate-(2/11), 'MM-DD-YYYY HH24')
but it only subtracts the hour; it does not touch the day itself.
Others have commented on the (incorrect) use of 2/11 to specify the desired interval.
I personally however prefer writing things like that using ANSI interval literals which makes reading the query much easier:
sysdate - interval '2' hour
It also has the advantage of being portable, many DBMS support this. Plus I don't have to fire up a calculator to find out how many hours the expression means - I'm pretty bad with mental arithmetics ;)
Try this:
SELECT to_char(sysdate - (2 / 24), 'MM-DD-YYYY HH24') FROM DUAL
To test it using a new date instance:
SELECT to_char(TO_DATE('11/06/2015 00:00','dd/mm/yyyy HH24:MI') - (2 / 24), 'MM-DD-YYYY HH24:MI') FROM DUAL
Output is: 06-10-2015 22:00, which is the previous day.
sysdate-(2/11)
A day consists of 24 hours. So, to subtract 2 hours from a day you need to divide it by 24:
DATE_value - 2/24
Using interval for the same:
DATE_value - interval '2' hour
date - n will subtract n days form given date. In order to subtract hrs you need to convert it into day buy dividing it with 24. In your case it should be to_char(sysdate - (2 + 2/24), 'MM-DD-YYYY HH24'). This will subract 2 days and 2 hrs from sysdate.
you should divide hours by 24 not 11
like this:
select to_char(sysdate - 2/24, 'dd-mon-yyyy HH24') from dual

SYSDATE but specify the time

I want to say the follow but substitute the date with SYSDATE but the time between is what I want to adjust. What would the syntax be?
where mydatefield between SYSDATE+'0001' and SYSDATE+'2359'
...
WHERE TO_CHAR( MOPACTIVITY.MOPNOTIFICATIONSENDAT , 'yyyy-mm-dd hh24:mi' )
BETWEEN '2013-07-26 00:00:01' AND '2013-07-26 23:59:59'
;
SYSDATE (or any other date column) in Oracle has the time component. So you need to strip that off and then add the hours/minutes/time condition.
Eg. to say current day 10:00 AM to 3:00 PM, you can say
date_column between (trunc(sysdate) + 10/24) and (trunc(sysdate) + 15/24)
Oracle date arithmetic works on the day level. so, +1 will give you the next day, 1/24 will give you an hour and 10/24 will give you 10:00 AM in the current day.
SQL> alter session set nls_date_format = 'DD-Mon-YYYY HH:MI:SS AM';
Session altered.
1 select sysdate,
2 trunc(sysdate),
3 trunc(sysdate) + 10/24,
4 trunc(sysdate) + 15/24
5* from dual
SQL> /
SYSDATE 26-Jul-2013 06:26:07 PM
TRUNC(SYSDATE) 26-Jul-2013 12:00:00 AM
TRUNC(SYSDATE)+10/24 26-Jul-2013 10:00:00 AM
TRUNC(SYSDATE)+15/24 26-Jul-2013 03:00:00 PM
For your question, you seem to be interested between current day and next day, so you can try adding + 1 to the date directly, once you strip the time component.
date_column >= trunc(sysdate) and
date_column < trunc(sysdate)+1
The best way to do this is to leave your MOPACTIVITY.MOPNOTIFICATIONSENDAT as a DATE type. That allows Oracle to optimize the query if there happens to be an index on the column. I'd recommend something like this:
WHERE MOPACTIVITY.MOPNOTIFICATIONSENDAT >= TRUNC(SYSDATE)
AND MOPACTIVITY.MOPNOTIFICATIONSENDAT < TRUNC(SYSDATE) + 1
That boils down to "greater than or equal to today at midnight" and "less than tomorrow at midnight".
We can also trunc both the dates and then compare the result
where TRUNC(MOPACTIVITY.MOPNOTIFICATIONSENDAT) = TRUNC(SYSDATE)
TRUNC Removes the timestamp from the dates