I have my table with EPOCH date system, i want to select data from previous month only. I have googled a lot but the only results i find is related to datetime system. Can you please help?
I will use this SQL Query to import data to Power BI.
You can convert your date range to an epoch using ( date_to_convert - DATE '1970-01-01' ) * 24 * 60 * 60 (assuming your epoch is in seconds since 1970).
You want to find values that are greater-than-or-equal-to the start of the previous month and before the start of the current month:
SELECT *
FROM your_table
WHERE epoch_column >= ( ADD_MONTHS( TRUNC(SYSDATE,'MM'), - 1 ) - DATE '1970-01-01' ) * 24 * 60 * 60
AND epoch_column < ( TRUNC( SYSDATE, 'MM' ) - DATE '1970-01-01' ) * 24 * 60 * 60
If you use midnight of the last day of the previous month as your upper bound then you will miss all values that are on that last day but are after midnight.
You can convert a unix epoch (number of seconds since January 1st, 1970) to a date as follows :
TO_DATE('01/01/1970', 'dd/mm/yyyy') + epoch_column / 60 / 60 / 24
The division turns the epoch into a number of days, that can be added to the original date.
If you want to filter this on the previous month, then :
TO_DATE('01/01/1970', 'dd/mm/yyyy') + epoch_column / 60 / 60 / 24
BETWEEN ADD_MONTHS(TRUNC(sysdate, 'mm'), -1)
AND LAST_DAY(ADD_MONTHS(TRUNC(sysdate, 'mm'), -1))
Or better yet :
epoch_column
BETWEEN
(
ADD_MONTHS(TRUNC(sysdate, 'mm'), -1)
- TO_DATE('01/01/1970', 'dd/mm/yyyy')
) * 60 * 60 * 24
AND (
LAST_DAY(ADD_MONTHS(TRUNC(sysdate, 'mm'), -1))
- TO_DATE('01/01/1970', 'dd/mm/yyyy')
) * 60 * 60 * 24
This solution should be more efficient, as no operation is performed on the column being filtered, hence it should be able to take advantage of an existing index on epoch_column.
Related
I'm trying to get the minute value from a Timestamp after a subtraction
First I made a subtraction:
Current Time - Target Time(INSP_FIN_DT)
(
TO_TIMESTAMP(TO_CHAR(SYSDATE,'YYYY-MM-DD HH24:MI:SS'),'YYYY-MM-DD HH24:MI:SS') -
TO_TIMESTAMP(INSP_FIN_DT,'YYYY-MM-DD HH24:MI:SS')
) AS REST_TIME
the output:
+00 00:09:44.000000
What I need:
09
I already tried
SELECT SUBSTR(REST_TIME, 7,2)
But the return is ever 00, even If I convert it to Char like:
SELECT SUBSTR(TO_CHAR(REST_TIME),7,2)
How can I solve it by query?
Information here https://dba.stackexchange.com/questions/53924/how-do-i-get-the-difference-in-minutes-from-2-timestamp-columns
select
round(
(SYSDATE - cast(<other_timestamp> as date))
* 24 * 60
) as diff_minutes
from <some_table>;
For my current implementation, I'll never have more than a hour, in this case I used the bellow solution:
SYSTIMESTAMP - TO_TIMESTAMP(INSP_FIN_DT,'YYYY-MM-DD HH24:MI:SS') AS REST_TIME
Select..
EXTRACT(MINUTE FROM REST_TIME) AS REST_MINUTES
In case of more than 60 minutes, I should use:
(EXTRACT(HOUR FROM REST_TIME) * 60)
+ EXTRACT(MINUTE FROM REST_TIME) AS REST_MINUTES
select *
from sample_table scr
where extract('epoch' from systimestamp - scr.created_date)/60 > :defaultTimeOut
This is a postgres query. Trying to convert this query into oracle.
How do I convert epoch in oracle?
TIA.
You are actually trying to convert an interval (ie the difference between two dates) to a number of seconds. Assuming that created_date is of date datatype, one method is:
select *
from sample_table
where (sysdate - created_date) * 24 * 60 * 60 > :defaultTimeOut
Rationale: in Oracle, substracting two dates returns a decimal number that represents the difference in days. You can multiply that by 24 (hours per day), 60 (minutes per hour) and 60 (seconds per minute) to convert that to a number of seconds, then compare it to the target value.
If created_date is of timestamp datatype, you can cast it to a date first:
select *
from sample_table
where (sysdate - cast(created_date as date)) * 24 * 60 * 60 > :defaultTimeOut
How to round up time interval to next day in Oracle SQL?
select apppackage
, numtodsinterval(
sum( trunc(extract (day from (periods)) * 86400
+ extract (hour from (periods)) *3600
+ extract (minute from (periods))*60
+ extract (second from (periods)))
), 'SECOND') as retention_period
, count(apppackage) as users
from retentions
where apppackage = 'com.Freesoul.Rotter'
group by apppackage;
The output of this is
'com.Freesoul.Rotter' '+2969 04:32:47.000000' '3'
and desired output is
'com.Freesoul.Rotter' '2970' '3'
but if the output of query is
'com.Freesoul.Rotter' '+2969 00:00:00.000000' '3'
then desired output is
'com.Freesoul.Rotter' '2969' '3'
column period is of INTERVAL DAY(9) TO SECOND(6) type
and i won't mind if the retention_period is changed to number datatype.
I'll be grateful if anyone can suggest change in my query to attain the desired output.
The result of your sum is in seconds, so you don't really need to convert it to an interval at all. Just divide by 60*60*24 to get the answer in days, and round it up with ceil():
select apppackage
, ceil(sum( trunc(extract (day from (periods)) * 86400
+ extract (hour from (periods)) *3600
+ extract (minute from (periods))*60
+ extract (second from (periods)))
) / 86400) as retention_period
, count(apppackage) as users
from retentions
where apppackage = 'com.Freesoul.Rotter'
group by apppackage;
Demo with artificial data in a CTE just to mimic your expected results, for both scenarios:
-- CTE for sample data
with retentions (apppackage, periods) as (
select 'com.Freesoul.Rotter', interval '+2967 04:32:47.000000' day(9) to second(6) from dual
union all
select 'com.Freesoul.Rotter', interval '1' day from dual
union all
select 'com.Freesoul.Rotter', interval '1' day from dual
union all
select 'com.Freesoul.XYZ', interval '+2967 00:00:00.000000' day(9) to second(6) from dual
union all
select 'com.Freesoul.XYZ', interval '1' day from dual
union all
select 'com.Freesoul.XYZ', interval '1' day from dual
)
-- actual query
select apppackage
, ceil(sum( trunc(extract (day from (periods)) * 86400
+ extract (hour from (periods)) *3600
+ extract (minute from (periods))*60
+ extract (second from (periods)))
) / 86400) as retention_period
, count(apppackage) as users
from retentions
where apppackage = 'com.Freesoul.Rotter'
-- extra clause for dummy data
or apppackage = 'com.Freesoul.XYZ'
group by apppackage;
APPPACKAGE RETENTION_PERIOD USERS
------------------- ---------------- ----------
com.Freesoul.XYZ 2969 3
com.Freesoul.Rotter 2970 3
Your expected output shows a plain number. If you actually want it as an interval, but as the whole number of days, just pass ceil'd number into numtodsinterval or more simply (and usually faster for some reason) multiply by interval '1' day.
With the same dummy data:
select apppackage
, ceil(sum( trunc(extract (day from (periods)) * 86400
+ extract (hour from (periods)) *3600
+ extract (minute from (periods))*60
+ extract (second from (periods)))
) / 86400) * interval '1' day as retention_period
, count(apppackage) as users
...
APPPACKAGE RETENTION_PERIOD USERS
------------------- --------------------- ----------
com.Freesoul.XYZ +2969 00:00:00.000000 3
com.Freesoul.Rotter +2970 00:00:00.000000 3
As #mathguy pointed out, you probably don't need or want the trunc() call in there; that is removing the fractional seconds from each period before they are summed, which sounds insignificant but could easily affect the result you get.
How about this?
CASE WHEN numtodsinterval(extract (day from periods), 'DAY') = periods THEN
extract (day from periods)
ELSE
extract (day from periods) + 1
END
I have a table (incident) that has column Create_date(DataType=Date).
I want to get difference in Days OR Hours from Previous Record. Like the screenshot below.
From Second Record Create_Date I want to minus First Create_Date and from Third Create Date to Second and so on. I'm using LAG function in Oracle, but not sure how its calculating there. Could any one please help me regarding that issue.
incident.create_date - lag(incident.create_date,1) OVER (ORDER BY incident.create_date) AS CREATEDATE_DIFF,
RN 1 We have Create_date (05/01/017 10:40:17 AM
Date differences in Oracle are calculated in numbers of days. If the difference is less than a day, you're going to get a value of less than 1 returned.
If you want to convert that into hours, you'll have to multiply the result by 24, for minutes multiply by 24*60 and for seconds it's 24*60*60.
e.g.:
select sysdate - trunc(sysdate) diff_in_days,
(sysdate - trunc(sysdate))*24 diff_in_hours,
(sysdate - trunc(sysdate))*24*60 diff_in_mins,
(sysdate - trunc(sysdate))*24*60*60 diff_in_secs
from dual;
DIFF_IN_DAYS DIFF_IN_HOURS DIFF_IN_MINS DIFF_IN_SECS
------------ ------------- ------------ ------------
0.4342245370 10.4213888888 625.28333333 37517
You may then wish to apply ROUND (or maybe TRUNC/CEIL) depending on how you want the output to look like (e.g. to 2 d.p., to nearest minute, etc).
If you subtract one date from another you will get the difference in days (or fractions thereof) as a number.
You can get the days/hours/minutes/seconds of this using an interval:
SELECT EXTRACT( DAY FROM createdate_diff ) AS days,
EXTRACT( HOUR FROM createdate_diff ) AS hours,
EXTRACT( MINUTE FROM createdate_diff ) AS minutes,
EXTRACT( SECOND FROM createdate_diff ) AS seconds,
createdate_diff
FROM (
SELECT NUMTODSINTERVAL(
create_date - lag(create_date) OVER (ORDER BY create_date),
'DAY'
) AS CREATEDATE_DIFF
FROM incident
);
Or you can perform the same calculations manually:
SELECT TRUNC( createdate_diff ) AS days,
TRUNC( MOD( createdate_diff * 24, 24 ) ) AS hours,
TRUNC( MOD( createdate_diff * 24 * 60, 60 ) ) AS minutes,
MOD( createdate_diff * 24 * 60 * 60, 60 ) AS seconds,
createdate_diff
FROM (
SELECT create_date - lag(create_date) OVER (ORDER BY create_date)
AS CREATEDATE_DIFF
FROM incident
);
Use
......
(incident.create_date -
lag(incident.create_date,1) OVER (ORDER BY incident.create_date))
*24*60
AS CREATEDATE_DIFF_IN_MINS,.....
to get the output in minutes, which seams suitable for your sample data. Or multiply further by 60 to get output in seconds.
I have come across a query which has me curious whether the programmer was show boating or whether there is merit to the way it has been done in terms of performance. I have no clue as to why the from time is 01:59 rather than 00:00, this would actually remove some of the results that would actually want to be included.
This is the where clause of the query
WHERE REPORTDATE BETWEEN TRUNC(SYSDATE - 21) + 01 / 24 + 59 / (24 * 60) + 59 / (24 * 60 * 60)
AND TRUNC(SYSDATE) + 23 / 24 + 59 / (24 * 60) + 59 / (24 * 60 * 60)
and if my math is correct, is the same as
WHERE REPORTDATE BETWEEN to_date('13/04/2017 01:59','dd/mm/yyyy hh24:mi')
AND to_date('04/05/2017 23:59','dd/mm/yyyy hh24:mi')
Is there any benefit in the first calculated where clause over the second?
You can use interval literals to get rid of all the arithmetic and simplify the query:
WHERE REPORTDATE BETWEEN TRUNC( SYSDATE ) - INTERVAL '20 22:00:01' DAY TO SECOND
AND TRUNC( SYSDATE ) + INTERVAL '00 23:59:59' DAY TO SECOND
or
WHERE REPORTDATE BETWEEN TRUNC( SYSDATE ) - INTERVAL '21' DAY
+ INTERVAL '01:59:59' HOUR TO SECOND
AND TRUNC( SYSDATE ) + INTERVAL '00 23:59:59' DAY TO SECOND
or
WHERE REPORTDATE >= TRUNC( SYSDATE ) - INTERVAL '20 22:00:01' DAY TO SECOND
AND REPORTDATE < TRUNC( SYSDATE ) + INTERVAL '1' DAY
It is hard to imagine a performance difference, based on different ways of calculating constants in a query.
I would write this using something like this:
WHERE REPORTDATE >= CAST(TIMESTAMP '2017-04-13 02:00:00' as DATE) and
REPORTDATE < DATE '2017-05-05'
If you are going to include date/time constants, use the built-in mechanisms that support standard formats.
or for more flexibility based on the current date:
WHERE REPORTDATE >= TRUNC(sysdate) - 21 + 2 / 24 AND
REPORTDATE < TRUNC(sysdate) + 1
(or, if 1:59 is really intended . . . then TRUNC(sysdate) - 21 + (1 * 60 + 59) / (24 * 60).)