How to Round Decimal Result of a Calculated Column in Oracle SQL - sql

I have a calculated column in Oracle that returns a number that is very long because of decimals (ex: 200000.0044068030021345452041589203332645).
Is there a way to convert this to say 200000.00? I tried Round, TO_DECIMAL, CAST. But nothing seems to work.
SELECT
CASE
WHEN TRD = 'FUT'
THEN
CASE
WHEN BUY_SELL = 'BUY'
THEN CUR / PRC
ELSE -CUR / PRC
END
ELSE NULL
END AS UNITS
FROM LAN.Details

use round
select round(200000.0044068030021345452041589203332645,2) from dual
so in your query
SELECT
CASE
WHEN TRD = 'FUT'
THEN
CASE
WHEN BUY_SELL = 'BUY'
THEN round( CUR / PRC ,2)
ELSE round(-CUR / PRC,2)
END
ELSE NULL
END AS UNITS
FROM LAN.Details

Related

Overflow error when using the sum function?

I'm writing a query to calculate how much more the average customer has transacted and spent since signing up with my company. However, it returns the error message "Overflow occurred during numeric data type conversion".
The problem is definitely this bit, as when I comment it out the query runs successfully:
SUM(SALES_GROWTH_PERCENT)
Google tells me it's likely that I'm trying to fit a number with too many decimal places into a field that's too short for it. However, I've tried changing how many decimal places the case statements are using with no luck.
Edit: for context, here are the details of the fields being used, from syscat.columns:
This is the query in question. Can anyone see where I'm going wrong please? Any advice would be appreciated!
SELECT SUM(TRANS_GROWTH_PERCENT)/COUNT(CUSTOMER_ID) AS AVG_TRANS_GROWTH_PERCENT,
SUM(SALES_GROWTH_PERCENT)/COUNT(CUSTOMER_ID) AS AVG_SALES_GROWTH_PERCENT
FROM
(
SELECT CUSTOMER_ID,
CASE WHEN POST_SIGNUP_TRANS <=0
THEN 0
WHEN POST_SIGNUP_TRANS >0
THEN CAST((CAST(POST_SIGNUP_TRANS AS DECIMAL (10,5)) - CAST(PRE_SIGNUP_TRANS AS DECIMAL (10,5))) / CAST(PRE_SIGNUP_TRANS AS DECIMAL (10,5)) * 100 AS DECIMAL (10,1))
ELSE NULL
END AS TRANS_GROWTH_PERCENT,
CASE WHEN POST_SIGNUP_SALES <=0
THEN 0
WHEN POST_SIGNUP_SALES >0
THEN CAST((CAST(POST_SIGNUP_SALES AS DECIMAL (10,5)) - CAST(PRE_SIGNUP_SALES AS DECIMAL (10,5))) / CAST(PRE_SIGNUP_SALES AS DECIMAL (10,5)) * 100 AS DECIMAL (10,1))
ELSE NULL
END AS SALES_GROWTH_PERCENT
FROM
(
SELECT CUSTOMER_ID,
SUM(PRE_SIGNUP_TRANS) AS PRE_SIGNUP_TRANS, SUM(PRE_SIGNUP_SALES) AS PRE_SIGNUP_SALES,
SUM(POST_SIGNUP_TRANS) AS POST_SIGNUP_TRANS, SUM(POST_SIGNUP_SALES) AS POST_SIGNUP_SALES
FROM
(
SELECT CUSTOMER_ID,
CASE WHEN TRANSACTION_DATE >= ANALYSIS_START_DATE THEN 1 ELSE 0 END AS ANALYSIS_FLAG,
CASE WHEN TRANSACTION_DATE < SIGNUP_DATE THEN 1 ELSE 0 END AS PRE_SIGNUP_TRANS,
CASE WHEN TRANSACTION_DATE < SIGNUP_DATE THEN SALES ELSE 0 END AS PRE_SIGNUP_SALES,
CASE WHEN TRANSACTION_DATE >= SIGNUP_DATE THEN 1 ELSE 0 END AS POST_SIGNUP_TRANS,
CASE WHEN TRANSACTION_DATE >= SIGNUP_DATE THEN SALES ELSE 0 END AS POST_SIGNUP_SALES
FROM TRANSACTIONS_TABLE
)
WHERE ANALYSIS_FLAG = 1
GROUP BY CUSTOMER_ID
)
WHERE PRE_SIGNUP_TRANS >0
AND PRE_SIGNUP_SALES >0
)
;

Need to get null back rather than divide by zero

I had to change my old query to a new query to get the correct results. My old query used to return a null in the denominator, so I didn't have to worry about divide by zero, the new query returns divide my zero for 'M' (R_NTWK_CHNNL), but for 'S' or R, i don't have a zero denominator. What can I do to get a null denominator in query 2? The table definition didn't change and wondering why now I don't get a null denominator when 'M' has nothing in it. Please also, how would I add nullif to the query 2? Thank you very much.
Old query
select SUM(CASE WHEN (GNRC_CD in ('O') and R_NTWK_CHNNL = 'M') then (CLNT_NET_DUE_AMT + NBNR_CLNT_NET_DUE_AMT) else 0 end ) / sUM(CLMS) from #Clms_SMRY where SRVC_DT between #CurrentBeginDate and #CurrentEndDate)
New query
select SUM(CASE WHEN (GNRC_CD in ('O') ) and R_NTWK_CHNNL = 'M' then (CLNT_NET_DUE_AMT + NBNR_CLNT_NET_DUE_AMT) else 0 end ) / cast(SUM(CASE WHEN GNRC_CD in ('O') and R_NTWK_CHNNL = 'M' then (CLMS) end ) as float) from #Clms_Smry where SRVC_DT between #CurrentBeginDate and #CurrentEndDate),
Use NULLIF():
select (SUM(CASE WHEN (GNRC_CD in ('O') and R_NTWK_CHNNL = 'M') then (CLNT_NET_DUE_AMT + NBNR_CLNT_NET_DUE_AMT) else 0 end ) /
NULLIF(SUM(CLMS), 0)
)
from #Clms_SMRY
where SRVC_DT between #CurrentBeginDate and #CurrentEndDate)

Oracle view - sum to variable

How can i shorten the following select statement?
create or replace view V_AMV_PLG_QUOTES_50_MS as
select
sum(NVL(ASK_SIZE,0)) as ASK_VOLUME,
CASE WHEN
sum(CASE WHEN NVL(ASK_SIZE,0)=0 THEN CASE WHEN BASE_CURR_ASK_PRICE=0 THEN 0 ELSE 1 END ELSE ASK_SIZE END)=0 THEN 1
ELSE sum(CASE WHEN NVL(ASK_SIZE,0)=0 THEN CASE WHEN BASE_CURR_ASK_PRICE=0 THEN 0 ELSE 1 END ELSE ASK_SIZE END) END as ASK_PRICE,
EXCHANGE_SK as EXCHANGE_SK,
PRODUCT_SK as PRODUCT_SK,
BUSINESS_DATE as BUSINESS_DATE
from
S_AMV_PLG_QUOTE_AGG quotes
where NVL(BASE_CURR_ASK_PRICE ,0) > 0
group by
EXCHANGE_SK,
PRODUCT_SK,
BUSINESS_DATE
Notice the very long calculation appears twice.. Can i insert it into a variable somehow? And just use the CASE operator on the Variable? (Notice we have a sum function there..)
You can't use create and use a variable within a view. If you just want to avoid repeating the nested case statement, you could move it (and the NVL) into an in-line view:
select
sum(MY_ASK_SIZE) as ASK_VOLUME,
CASE WHEN sum(MY_ASK_PRICE)=0 THEN 1
ELSE sum(MY_ASK_PRICE)
END as ASK_PRICE,
EXCHANGE_SK as EXCHANGE_SK,
PRODUCT_SK as PRODUCT_SK,
BUSINESS_DATE as BUSINESS_DATE
from (
select
EXCHANGE_SK, PRODUCT_SK, BUSINESS_DATE,
NVL(ASK_SIZE,0) as MY_ASK_SIZE,
CASE WHEN NVL(ASK_SIZE,0)=0 THEN
CASE WHEN BASE_CURR_ASK_PRICE=0 THEN 0 ELSE 1 END
ELSE ASK_SIZE
END AS MY_ASK_PRICE
from S_AMV_PLG_QUOTE_AGG quotes
where NVL(BASE_CURR_ASK_PRICE ,0) > 0
)
group by
EXCHANGE_SK,
PRODUCT_SK,
BUSINESS_DATE;
The NVL and case are performed once, and aliased as MY_ASK_SIZE and MY_ASK_PRICE respectively; and those aliases are then used in the outer query, including within the sum.
If you want to avoid repeating the SUM too, move that into the in-line view as well, along with the group-by clause:
select
ASK_VOLUME as ASK_VOLUME,
CASE WHEN ASK_PRICE=0 THEN 1
ELSE ASK_PRICE
END as ASK_PRICE,
EXCHANGE_SK as EXCHANGE_SK,
PRODUCT_SK as PRODUCT_SK,
BUSINESS_DATE as BUSINESS_DATE
from (
select
EXCHANGE_SK, PRODUCT_SK, BUSINESS_DATE,
SUM(NVL(ASK_SIZE,0)) as ASK_VOLUME,
SUM(CASE WHEN NVL(ASK_SIZE,0)=0 THEN
CASE WHEN BASE_CURR_ASK_PRICE=0 THEN 0 ELSE 1 END
ELSE ASK_SIZE
END) AS ASK_PRICE
from S_AMV_PLG_QUOTE_AGG quotes
where NVL(BASE_CURR_ASK_PRICE ,0) > 0
group by
EXCHANGE_SK,
PRODUCT_SK,
BUSINESS_DATE
);
Most of your column aliases are redundant but I've stuck with your pattern.
This is largely cosmetic though; Oracle's optimiser is likely to be clever enough to only perform the actual calculation once anyway, so I wouldn't expect to see much (or any) performance difference.
I used creation of a simple ifZeroReturnOne function:
CREATE OR REPLACE FUNCTION ifZeroReturnOne (expr IN NUMBER)
RETURN NUMBER
IS retval NUMBER;
BEGIN
SELECT CASE WHEN expr=0 THEN 1
ELSE expr END
INTO retval
FROM DUAL;
RETURN (retval);
END;
Than I used in the query:
select sum(NVL(ASK_SIZE,0)) as ASK_VOLUME,
ifZeroReturnOne (sum(CASE WHEN NVL(ASK_SIZE,0)=0 THEN CASE WHEN BASE_CURR_ASK_PRICE=0 THEN 0 ELSE 1 END ELSE ASK_SIZE END) as ASK_PRICE,
EXCHANGE_SK as EXCHANGE_SK,
etc...............
Let me know if you have better suggestions

SQL Query for abandonment rate calculation for Shoretel Reports

Can someone check my query it does not seem to be executing. I am tring to get the abandonment Rate percentage from callsAgent and CallsAbandoned = to abandomnet % 98.45. The fields in 'column' are a column.
Formula should be: CallsAbandoned >0 or CallsAgent >0 then CallsAbandoned / CallsAgent *100
CASE WHEN 'callsadandoned' > 0 OR 'callsagent' > 0
THEN 'callsadandoned' / 'callsagent' *100 END
AS AdnandonmentRate
SELECT queuecall1.StartTime,
queuecall1.TargetDN,
queuecall1.TargetType,
queuecall1.QueueDN,
queuecall1.QueueName,
queuecall1.DurationSeconds,
queuecall1.CallID,
call1.CallType,
queuecall1.Duration,
queuecall1.ExitReason,
datename(mm, queuecall1.StartTime) AS Month,
datename(YYYY, queuecall1.StartTime) AS Year,
datename(DW, queuecall1.StartTime) AS Weekday,
datename(QQ, queuecall1.StartTime) AS Quarter,
datename(WK, queuecall1.StartTime) AS Week,
CASE WHEN ExitReason = 7 THEN 1 ELSE 0 END AS CallsAbandoned,
CASE WHEN ExitReason = 1 THEN 1 ELSE 0 END AS CallsAgent,
CASE WHEN calltype = 1 THEN 1 ELSE 0 END AS CallsInternal,
CASE WHEN calltype = 2 THEN 1 ELSE 0 END AS CallsExternal,
CASE
WHEN exitreason = 9
AND targettype = 3
AND targetdn = queuedn
OR exitreason IN ( 2, 3, 4, 5 )
AND targettype = 3 THEN 1 ELSE 0 END AS CallsVM,
CASE WHEN (ExitReason = 9) AND
TargetDN <> QueueDN OR
ExitReason = 10 OR
ExitReason = 11 THEN 1 ELSE 0 END as CallsTransfered,
CASE WHEN CallsAbandoned > 0 OR CallsAgent > 0 THEN CallsAbandoned / CallsAgent *100 END AS AdnandonmentRate
FROM (queuecall queuecall1 INNER JOIN connect connect1
ON queuecall1.ConnectTableID=connect1.ID) INNER JOIN call call1
ON connect1.CallTableID=call1.ID
The error i am getting is: Msg 8117, Level 16, State 1, Line 31
Operand data type varchar is invalid for divide operator.
Any Assitance would be great.
Thanks,
Arron
By placing apostrophe's around the column names you are treating them as individual varchar (text) values and not column names. Which the error is correctly saying cannot be used when dividing.
If you remove these, it will instead know that you are referring to a column name. Assuming the values in your columns are of the applicable type that can be divided. The following should work:
CASE WHEN callsadandoned > 0 OR callsagent > 0
THEN callsadandoned / callsagent *100 END
AS AdnandonmentRate

How to modify my code to set sum/avg to negative if any one value is negative

Below is my existing SQL code (sql server) that didn't check for error values. It simply calculates a sum column and an average column if the month and year values match.
SELECT ur.Domain, SUM(ur.DataUsageInBytes) as SumDataUsageInBytes,
AVG(ur.DiskUsageInBytes) as AvgDiskUsageInBytes
FROM UsageResults ur
WHERE (ur.Year = #year) AND (ur.Month = #month)
GROUP BY [Domain]
I want to add logic such that if any ur.DataUsageInBytes value(for the given month/year) is negative I want to set the sum to say -99, otherwise I'll just compute the normal sum. The same goes for the average.
The table entries it is reading will have negative values if there was an error encountered and their values couldn't be determined.
SELECT ur.Domain
, case
when min(ur.DataUsageInBytes) < 0 then -99
else sum(ur.DataUsageInBytes)
end as SumDataUsageInBytes
, case
when min(ur.DataUsageInBytes) < 0 then -99
else avg(ur.DataUsageInBytes)
end as AvgDiskUsageInBytes
FROM UsageResults ur
WHERE ur.Year = #year AND ur.Month = #month
GROUP BY
ur.Domain
you could turn each value into a positive and compare sums
SELECT ur.Domain
, CASE WHEN SUM(ur.DataUsageInBytes) = SUM(ABS(ur.DataUsageInBytes)) THEN SUM(ur.DataUsageInBytes) ELSE -99 END as SumDataUsageInBytes
, CASE WHEN min(ur.DiskUsageInByters) < 0 THEN -99 ELSE AVG(ur.DiskUsageInBytes) END AS AvgDiskUsageInBytes
FROM UsageResults ur
WHERE (ur.Year = #year) AND (ur.Month = #month)
GROUP BY [Domain]