convert from time in format h.mm to minutes - oracle

I have time stored as number in an oracle database in the format hh.mm, I want to calculate the sum and then write it back in another column in the same format hh.mm using a store procedure.
Is there any function in oracle for this type of summation or I have to do it from scratch?
Thanks in advance.

You are storing values in a custom format. So obviously Oracle won't a built-in function to handle it.
Doing this requires a series of steps, which could be wrapped into a user-defined function.
Convert the numeric column into a string. It is important to specify the format mask, otherwise the next step will produce the wrong result
Use regular expressions to extract the hour and minute values from the column
Derive the total number of minutes with simple arithmetic
Derive the new total number of hours and remainder of minutes with simple arithmetic
Derive the final number as a pseudo-decimal value.
Here is the SQL ...
select hh + (mi/100) as final_result
from (
select trunc(step3.tot_mins/60) as hh
, step3.tot_mins - (trunc(step3.tot_mins/60)*60) as mi
from (
select sum((step2.hh*60)+step2.mi) as tot_mins
from (
with step1 as (select to_char(ctime, '00000000000.99') ctime
from your_table)
select to_number(regexp_substr(ctime, '([0-9]+)', 1,1)) as hh
, to_number(regexp_substr(ctime, '([0-9]+)', 1, 2)) as mi
from step1
) step2
) step3
) step4
/
... and here is the obligatory SQL Fiddle.

Related

Elegant way to make a SUm

I need a query (in Oracle), that will be inside a stored procedure, where I can get a sum of the Amount value of Table REV.
The YEAR and one MONTH will be received as a parameter in the stored procedure, as YY and MM.
What I want is to sum the amount values since the 1st month of the year UP to the MM passed in the argument.
So
if MM in the argument is 02, I want to take the sum of amounts of months 01 + 02
if MM in the argument is 05, I want to take the sum of amounts of months 01+02+03+04+05
So MM is the last month to be summed.
How can I make this in the most efficient and elegant way?
CREATE OR REPLACE PROCEDURE "GET_YTD_AMOUNT" (YY in VARCHAR,
MM in VARCHAR)
select
ACT.LABEL ,
R.YEAR,
R.MONTH,
sum(R.AMOUNT)
from
ACTIVITY ACT,
REV R
where
R.YEAR=YEAR and
R.MONTH ??
R.ID_CODE = ACT.ID_CODE
I'd prefer using numeric variables rather than strings for such cases.
In your case ;
considering your year and month parameters are of string type, you need a to_number() conversion with less than or equal to operator
to_number(R.MONTH) <= to_number(i_month)
add an out parameter o_amount to return the result you get
of course, you need to convert your SQL format containing explicit
joins
better to define parameters ( or local variables ) by their type
within the tables in which they're contained. Btw, I didn't define o_amount by rev.amount%type against probability of sum() aggregation might exceed the precision of numeric value provided it's defined as so within the table.
So,use :
CREATE OR REPLACE PROCEDURE GET_YTD_AMOUNT(
i_year in rev.year%type,
i_month in rev.month%type,
o_amount out number
) IS
BEGIN
select sum(r.amount)
into o_amount
from activity a
join rev r
on r.id_code = a.id_code
where r.year = i_year
and to_number(r.month) <= to_number(i_month);
END;
/
You can use less than equal to:
select
ACT.LABEL ,
R.YEAR,
Max(R.MONTH) || '-' || Max(R.MONTH) as months_from_to
sum(R.AMOUNT)
from
ACTIVITY ACT,
REV R
where
R.YEAR= YY and -- it should be YY
R.MONTH <= MM -- less than equal to with MM
R.ID_CODE = ACT.ID_CODE
Group by ACT.LABEL ,
R.YEAR
Note: You must re-design your DB to store dates in date data type.
Cheers!!

DAX - Meassure that sums only the first occurance by group

I'm trying to figure out how to build a measure that sums a total, but only taking the first non-empty row for a user.
For example, my data looks like the below:
date user value
-----------------
1/1/17 a 15
2/1/17 a 12
1/1/17 b null
5/1/17 b 3
I'd therefore like a result of 18 (15 + 3).
I'm thinking that using FIRSTNONBLANK would help, but it only takes a single column, I'm not sure how to give it the grouping - perhaps some sort of windowing is required.
I've tried the below, but am struggling to work out what the correct syntax is
groupby(
GROUPBY (
myTable,
myTable[user],
“Total”, SUMX(CURRENTGrOUP(), FIRSTNONBLANK( [value],1 ))
),
sum([total])
)
I didn't have much luck getting FIRSTNONBLANK or GROUPBY to work exactly how I wanted, but I think I found something that works:
SUMX(
ADDCOLUMNS(
ADDCOLUMNS(VALUES(myTable[User]),
"FirstDate",
CALCULATE(MIN(myTable[Date]),
NOT(ISBLANK(myTable[Value])))),
"FirstValue",
CALCULATE(SUM(myTable[Value]),
FILTER(myTable, myTable[Date] = [FirstDate]))),
[FirstValue])
The inner ADDCOLUMNS calculates the first non-blank date values for each user in the filter context.
The next ADDCOLUMNS, takes that table of users and first dates and for each user sums each [value] that occurred on each respective date.
The outer SUMX takes that resulting table and totals all of the values of [FirstValue].

Difference in two dates not coming as expected in Oracle 11g

I get some data through a OSB Proxy Service and have to transform that using Xquery. Earlier the transformation was done on the database but now it is to be done on the proxy itself. So I have been given the SQL queries which were used and have to generate Xquery expressions corresponding to those.
Here is the SQL query which is supposed to find the difference between 2 dates.
SELECT ROUND((CAST(DATEATTRIBUTE2 AS DATE) -
CAST(DATEATTRIBUTE1 AS DATE) ) * 86400 ) AS result
FROM SONY_TEST_TABLE;
DATEATTRIBUTE1 and DATEATTRIBUTE2 are both of TIMESTAMP type.
As per my understanding this query first casts the TIMESTAMP to DATE so that the time part is stripped then subtracts the dates. That difference in days in multiplied with 86400 to get the duration in seconds.
However, when I take DATEATTRIBUTE2 as 23-02-17 01:17:19.399000000 AM and DATEATTRIBUTE1 as 23-02-17 01:17:18.755000000 AM the result should ideally be 0 as the dates are same and i'm ignoring the time difference but surprisingly the result comes as 1. After checking I found that the ( CAST(DATEATTRIBUTE2 AS DATE) - CAST(DATEATTRIBUTE1 AS DATE) ) part aparently does not give an integer value but a fractional one. How does this work?? o_O
Any help is appreciated. Cheers!
EDIT : So got the problem thanks to all the answers! Even after casting to DATE it still has time so the time difference is also calculated. Now how do I implement this in XQuery? See this other question.
Oracle DATE datatype is actually a datetime. So casting something as a date doesn't remove the time element. To do that we need to truncate the value:
( trunc(DATEATTRIBUTE2) - trunc(DATEATTRIBUTE1) )
you should try this to find difference by day
SELECT (trunc(DATEATTRIBUTE2) -
trunc(DATEATTRIBUTE1) ) AS result
FROM SONY_TEST_TABLE;
alternative 2
you can use extract like below:
SELECT ROUND (
EXTRACT (MINUTE FROM INTERVAL_DIFFERENCE) / (24 * 60)
+ EXTRACT (HOUR FROM INTERVAL_DIFFERENCE) / 24
+ EXTRACT (DAY FROM INTERVAL_DIFFERENCE))
FROM (SELECT ( TO_TIMESTAMP ('23-02-17 01:17:19', 'dd-mm-yy hh24:mi:ss')
- TO_TIMESTAMP ('23-02-17 01:17:17', 'dd-mm-yy hh24:mi:ss'))
INTERVAL_DIFFERENCE
FROM DUAL)

convert minutes to hh/mi/ss format in oracle query

I want to know the query which converts minutes to the format of hh/mi/ss in Oracle.I 've already seen lot of same questions from many forums but nothing helped me to get the exact result.
The query I used -Select to_char(to_date(mod(100,60),'mi'),'hh/mi/ss') from dual;
But I don't know how to get the hour value.Because mod function returns only the remainder I don't know how to take the quotient part and substitute into the hour field.
I suppose there are two ways of storing "minutes" in an Oracle database - you can either store them in a field whose datatype is INTERVAL DAY TO SECOND, or you can store them in a NUMBER. The simplest case to handle is the INTERVAL - in this case, the TO_CHAR function converts the value to a string of the form SDD HH:MM:SS.FFFFFF, where 'S' is sign ('+' or '-' as intervals can be positive or negative), DD = days, HH= hours, 'MM' = minutes, 'SS' = seconds, and 'FFFFFF' = fractions; thus, to get the HH:MI:SS all we need to do is use the SUBSTR function, as in
SUBSTR(TO_CHAR(I_VAL), 5, 8)
where I_VAL is an INTERVAL DAY TO SECOND value.
If the value to be converted is in a numeric field it gets a bit messy as we have to compute the individual field values, then subtract the previous fields as part of getting the next field. However, since the value stored is in minutes instead of seconds it's not particularly difficult:
create table TST (N_VAL NUMBER,
I_VAL INTERVAL DAY TO SECOND);
INSERT INTO TST(N_VAL, I_VAL) VALUES (666, INTERVAL '666' MINUTE);
SELECT N_VAL,
TRUNC(N_VAL/60) AS HOURS,
N_VAL-(TRUNC(N_VAL/60) * 60) AS MINUTES,
0 AS SECONDS,
TO_CHAR(I_VAL),
SUBSTR(TO_CHAR(I_VAL), 5, 8) AS HMS_FROM_INTERVAL
FROM TST;
SQLFiddle here
Best of luck.

Always display decimal at the end of the integer in oracle

I have a requirement where i always need to display the number with the decimal point.
The datatype of the db column is that of number.
If the value is 1.25 it gets displayed as 1.25
But if the value is 1 it does gets displayed as 1 and I need to display the value as 1.00.
I need to perform rpad (right padding) operations once I get the result in the decimal format.
Without the decimal, the value of a whole number would be different from what is present in the database.
Example:
SELECT RPAD(ROUND(12,2), 5 ,0) AS test
FROM DUAL;
results in 12000 whereas I am expecting it to be 12.00.
Any pointers on this would help.
Thanks!
Use an appropriate to_char call. Something like
SELECT to_char( <<your number>>, '0.00' )
FROM dual;
That will return the string "1.00" when you pass in a value of 1. If you pass in a value of 0, it will return the string "0.00". If you pass in a a value of 1.25, it will return the string "1.25".
Try using a number format along with the TO_CHAR function, as:
SELECT TO_CHAR(12, 99.99) AS test
FROM DUAL;
Reference:
You can find documentatation related to other ways to format numbers here.
Try this:
select TRIM(to_char(100.5, '99999999.00')) FROM DUAL
The format specifications are here:
http://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements004.htm#i34570

Resources