How to remove the decimals when Subtracting casted Dates (EPOCH) in SQL Developer - sql

I am subtracting two epoch dates from each other to get a positive Integer that shows the number of days that has passed from creation to completion (aka modification).
Here is a snippet from my query, that accomplishes that from SQL Developer 20.2.0:
(TO_DATE('19700101', 'YYYYMMDD') + (DATEMODIFIED / 86400))-(TO_DATE('19700101', 'YYYYMMDD') + (DATECREATED / 86400)) AS "Age at Completion",
However, this results in an output of:
74.2922256787899889869
I don't need to see all those decimal places. A result such as this would be sufficient:
74.2922256787899889869 = 74
or
74.5922256787899889869 = 74
I think the ROUND function might be what I am looking for but I have no clue how to actually use it in that line. Can someone please assist? Thank you in advance.

(A + B) - (A + C) == A + B - A - C == B - C
So why not simply ROUND((DATECREATED - DATEMODIFIED) / 86400)?
Or maybe this:
DATEMODIFIED * INTERVAL '1' SECOND - DATECREATED * INTERVAL '1' SECOND
EXTRACT(DAY FROM (DATECREATED - DATEMODIFIED) * INTERVAL '1' SECOND)

Related

How to migrate from oracle to postgre using "WITH RECURSIVE" and "REGEXP_SUBSTR"?

There is code on oracle, how to port it to postgre without increasing it much?
SELECT pl.rd,
pl.rs,
pl.agency_plan,
pl.o__id
FROM ALIS.PLAF pl
WHERE RD BETWEEN to_date('01.'||pMM||'.'||pYYYY, 'dd.mm.yyyy') AND last_day(to_date('01.'||pMM||'.'||pYYYY, 'dd.mm.yyyy'))
AND RS IN (SELECT TO_CHAR(REGEXP_SUBSTR(str, '[^,]+', 1, LEVEL)) RS
FROM (SELECT TO_CHAR(P_RS_LIST) str
FROM dual) t CONNECT BY INSTR(str, ',', 1, LEVEL - 1) > 0);
When migrating a database to another (or really any other migration) an absolutely essential step is to analyze in detail what the old system is doing then translate into the new. A good read on this: Migrate your mindset. So what is the Oracle doing? First the section beginning and rs in. The following selects take a comma separated string (P_RS_LIST) and parses it into a set of individual elements to construct the in list. A Postgres equivalent being the string_to_table() function. Now for the section where rd between .... This section first creates a date of the specified year (pYYYY) and month (pMM) then uses the last_date() function to get the last day of that month. Postgres does not have that function, but the same result is achieved by adding interval - '1 month - 1 day' to the same derived date. Postgres could use to_date() to get the date but I find the make_date() function more convenient. So make_date(pYYYY, pMM,1) and make_date(pYYYY, pMM,1) + interval '1 month - 1 day' gets the same respective dates. Putting it all back together we get the query:
select *
from plaf
where rd between make_date(pyyyy, pmm, 1)
and (make_date(pyyyy, pmm, 1) + interval '1 month - 1 day')::date
and rs in (select string_to_table(p_rs_list,','));
I hope that does not increase it too much.
The names p... seems to imply this Oracle query runs within a procedure/function. If this is the case you can create a Postgres function as:
create or replace function match_plaf( pyyyy integer
, pmm integer
, p_rs_list text
)
returns setof plaf
language sql
as $$
select *
from plaf
where rd between make_date(pyyyy, pmm, 1)
and (make_date(pyyyy, pmm, 1) + interval '1 month - 1 day')::date
and rs in (select string_to_table(p_rs_list,','))
;
$$;
Note Not tested as no test data supplied.

Get difference between day just when the difference is positive

Using Postgresql, I need to substract two dates and to show the result just when the result of the difference between dates is positive or 0. In order to substract the dates I am using this:
SELECT
EXTRACT(EPOCH FROM ('2019-02-11 17:59:01.953894'::timestamp - '2019-12-09 02:08:16.01493'::timestamp))/60
However, I would need something like this:
SELECT
DECODE(SIGN(EXTRACT(EPOCH FROM ('2019-02-11 17:59:01.953894'::timestamp - '2019-12-09 02:08:16.01493'::timestamp))/60 as d),-1, None,
,1, d)
Running the previous query, I am getting an error in the following:
ERROR: syntax error at or near "as"
LINE 2: ...mestamp - '2019-12-09 02:08:16.01493'::timestamp))/60 as df)
^
Do you have an idea how to get over this?
Thanks a lot
You could use GREATEST to turn negative values to 0:
GREATEST(
EXTRACT(EPOCH FROM (ts1 - ts2))/60,
0
)
Or, if you want a null result when the difference is negative, you can use a case expression that compares the timestamps before attempting to substract them:
CASE WHEN ts1 > ts2 THEN EXTRACT(EPOCH FROM (ts1 - ts2))/60 END
Try this:
SELECT greatest((EXTRACT(epoch from age('2019-02-11', now())) / 86400)::int, 0)

Beginner Question (Oracle SQL) - Error with Varchar and SUM

I'm currently using Oracle SQL Developer to learn PL/SQL at university. I'm facing a problem where I had to import a .csv file to a table and have to sum up all elements of a column called TIME (composed of minutes, seconds and milliseconds).
However, the column is consisted of VARCHAR and the format is as of below:
TIME
01:00.250
02:37.408
01:29.803
...
I keep getting an error, mostly because there are non-numeric characters (":" and ".") on the column and hence the sum cannot be done. I checked on other topics and saw people saying to use TO_CHAR, TO_DATE, but none solutions seems to work.
Is there a better/easy approach for this problem?
Any help would be appreciated. :)
Oracle doesn't have a time data type. So, if you want to sum these, a simplish method is to convert the values to seconds:
select sum( to_number(substr(time, 1, 2)) * 60 +
to_number(substr(time, 4))
) as seconds
To convert the value back to a string representation of a number:
select floor(seconds / 60) || ':' || (case when seconds < 10 then '0' || mod(seconds, 60) else '' || mod(seconds, 60) end) as mmss
from (select (sum( to_number(substr(time, 1, 2)) * 60 +
to_number(substr(time, 4))
) as seconds
. . .
) s

Oracle sql: ORA-01830 when date calculation happens

I want to perform following oracle SQL query
SELECT t1.Technology, count(t1.trax_id) as "Current number of items", to_char(to_date(max(round((SYSDATE - t1.time_event) * 24 * 60 * 60)),'sssss'),'hh24:mi:ss') as "max_ages"
from dm_procmon t1
group by t1.Technology;
The problem is the date substration formula.
I susbtract 2 dates from each other. This gives me a decimal value
(like 0,00855605). I want the value back to be a date value. So I
converted this first to a Number (Decimal > Number) and than to a
char (Number > Char) Finally from a char to date (Char > Date).
But when I perform the action I receive
Error report -
SQL Error: ORA-01830: Datumnotatieafbeelding eindigt voordat de gehele
invoerstring is geconverteerd.
01830. 00000 - "date format picture ends before converting entire input string"
What do I do wrong?
you try to convert to_date(%number of seconds%, 'sssss'), that is the problem. just use TO_CHAR(MAX(TO_DATE('20000101','yyyymmdd')+(SYSDATE - t1.time_event)),'hh24:mi:ss'); this will function correctly for intervals < 1day
here is a general solution without any limitations on maximum interval size:
select Technology, cnt as "Current number of items", FLOOR(x) || ':' || TO_CHAR(TO_DATE('20000101','yyyymmdd')+(x - FLOOR(x)),'hh24:mi:ss') as "max_ages"
from
(select t1.Technology, COUNT(t1.trax_id) cnt, MAX(SYSDATE - t1.time_event) x
from dm_procmon t1
group by t1.Technology);
FLOOR(x) returns the days and the rest (x - FLOOR(x)) is added to a constant date and transformed to hours, minutes and seconds
The following will give a DAY TO SECOND INTERVAL for all dates within about 68 years of one another:
SELECT t1.technology, COUNT(t1.trax_id) AS "Current number of items"
, NUMTODSINTERVAL(ROUND((SYSDATE - MIN(t1.time_event) * 24 * 60 * 60), 'SECOND') AS "max_ages"
FROM dm_procmon t1
GROUP BY t1.technology;
Note that rather that using MAX(SYSDATE - time), I used SYSDATE-MIN(time) (logically the same). The advantage of using this instead of TO_CHAR() is that you can then use the value returned in DATE/INTERVAL arithmetic.

SQL Command not properly ended ( oracle 11g for windows)

I m using this query to get a result of the difference between the start time and end time of an activity. Where the end time is null i wanted to put the minimum value as 500. Please advice and HELP!!
select * from table
where (end_time - start_time) * 24 * 60 > 1,
IF end_time IS NULL THEN '500';
So this is your query:
select * from table where (end_time - start_time) * 24 * 60 > 1;
But you want to treat a null end_time as 500. So use NVL or COALESCE to replace the null with 500:
select * from table where (nvl(end_time,500) - start_time) * 24 * 60 > 1;
IF end_time IS NULL THEN '500';
Just to make it more clear, '500' is not a number rather a string since it is enclosed within single quotation marks.
Now, end_time is. DATE data type or a timestamp, ideally. So, 500 makes no sense. You must convert it to appropriate type, whether 500 is days, hours, minutes, seconds, fraction of a second.
As in other answer it is suggested to use NVL(end_time, 500), it makes no sense. What does 500 - a date mean? Applying NVL is the need, however, you must convert it to the required value, else those are two different data types and Oracle won't allow it.
UPDATE
In my opinion,
Difference between two dates gives the number of days to the precision of seconds converted back to days. But, difference between an arbitrary number and a date makes no sense.
I assumed that start_time and end_time columns have number as datatype, for this calculation you need to select these specific columns and not all (*). Comparison is in where clause, this works in oracle11.
select ((NVL(END_TIME, 500)-START_TIME) * 24 * 60) from TABLE_NAME where ((NVL(END_TIME, 500)-START_TIME) * 24 * 60) > 1;