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
)
;
Related
I want to find the rate of negative and zero profits from a column. I tried to do it using aggregate and subquery but it doesn't seem to work as both method return 0 values.
The code is as follows
SELECT
COUNT(CASE WHEN profit < 0 THEN 1
END) AS negative_profits,
COUNT(CASE WHEN profit < 0 THEN 1
END) / COUNT(profit),
COUNT(CASE WHEN profit = 0 THEN 1
END) AS zero_profits,
COUNT(CASE WHEN profit = 0 THEN 1
END) / COUNT(profit)
FROM sales;
SELECT (SELECT COUNT(*)
FROM sales
WHERE profit <= 0)/COUNT(profit) AS n_negative_profit
FROM sales;
Both query return 0 in values
enter image description here
Avoid integer division, which truncates (like Adrian pointed out).
Also, simplify with an aggregate FILTER expression:
SELECT count(*) FILTER (WHERE profit <= 0)::float8
/ count(profit) AS n_negative_profit
FROM sales;
If profit is defined NOT NULL, or to divide by the total count either way, optimize further:
SELECT count(*) FILTER (WHERE profit <= 0)::float8
/ count(*) AS n_negative_profit
FROM sales;
See:
Aggregate columns with additional (distinct) filters
Because you are doing integer division per docs Math operators/functions.
numeric_type / numeric_type → numeric_type
Division (for integral types, division truncates the result towards zero)
So:
select 2/5;
0
You need to make one of the numbers float or numeric:
select 2/5::numeric;
0.40000000000000000000
and to make it cleaner round:
select round(2/5::numeric, 2);
0.40
I have the table testing(name,money) where I have to return a result where all of the money that is positive is total into deposit and the negative amounts will be withdraw. With the query below it says :"Subquery is only allowed to return a single column."
SELECT name, SUM(money) AS "deposit"
FROM testing
where money > 0 in
(SELECT name, SUM(abs(money)) AS "withdraw"
FROM testing
where money < 0 )
GROUP BY name;
p.s: i tried without the "In" and it's not working too
SELECT name,
SUM(case when money > 0 then money else 0 end) AS deposit,
SUM(case when money < 0 then money else 0 end) AS withdraw
FROM testing
GROUP BY name;
You can use the following SQL statement
SELECT name, SUM(money) AS "deposit"
FROM testing
where money > 0
AND money in
(
SELECT SUM(abs(money)) AS "withdraw"
FROM testing
where money < 0
)
GROUP BY name;
Let me know if it works! :)
I have the following query which returns a total dollar amount.
select sum(cast(dollars as dec)) from financials
This includes positive and negative values.
I would like 2 separate things:
How can I just query the positive dollar amounts? ie. I have 3 records, 10 , -5 , 10. result would be 20.
I want an absolute value as a sum. ie. I have 3 records, 10, -5, 10. the result would be 25.
thanks.
FOR 1) Use conditional SUM()
SELECT SUM( CASE WHEN dollars > 0 then dollars ELSE 0 END) as positive_sum,
SUM( CASE WHEN dollars < 0 then dollars ELSE 0 END) as negative_sum
FROM financials
FOR 2) use ABS()
SELECT SUM( ABS( dollars ) )
FROM financials
Please try below queries. Thanks.
1) select sum(cast(dollars as dec))
from financials
where dollars > 0;
2) select sum(cast(abs(dollars) as dec))
from financials;
You have two queries.solutions are as follows
1.
select sum(dollars) from financials
2.
select sum((case when dollars>0 then dollars end))+sum((case when dollars<0 then -1*dollars end)) from financials
I have the following code which tells me which line items are in and out of SLA.
How can I turn that into a %, so for example when I add them together it will show 98% SLA Met.
,CASE
WHEN m.COMPLETED_DT is NULL THEN ''
WHEN m.COMPLETED_DT <= m.SLA_ADJUSTED_DT THEN 'SLA Met'
WHEN m.SLA_ADJUSTED_DT IS NULL THEN 'SLA Met'
ELSE 'SLA Missed' END AS "SLA Desc"
If I had the result already, I think it would look something like...
SELECT (count(*) * 100 / (select count(*) FROM testtable)) AS YesSLA
FROM testtable where SLA='Yes';
I am not sure how to integrate that with my current statement, I don't believe I can reference the AS SLA Desc in a new statement.
Does this do what you want?
select 100 * avg(case when m.completed_dt <= m.SLA_ADJUSTED_DT or m.SLA_ADJUSTED_DT is null
then 1.0 else 0
end)
from testtable
where SLA = 'Yes';
The code below calculates the % met SLA out of 100 by counting only values that met SLA and then dividing by the total opportunities.
DECLARE #Data TABLE (COMPLETED_DT DATETIME, SLA_ADJUSTED_DT DATETIME)
INSERT #Data VALUES ('5/5/2014', '5/6/2014'), ('5/6/2014', '5/6/2014'), ('5/7/2014', '5/6/2014')
SELECT
CONVERT(FLOAT, SUM(CASE WHEN COMPLETED_DT <= SLA_ADJUSTED_DT THEN 1 ELSE 0 END)) * 100 / COUNT(1) AS [% Met SLA]
FROM #Data
Output
% Met SLA
----------------------
66.6666666666667
I have some fields in the table, need to average those fields.
Then I run this syntax, because I don't want to calculate 0 (zero) value.
SELECT myDate, AVG(CASE myField1 WHEN 0 THEN NULL ELSE myField1 END) AS avgmyField1
FROM myTable WHERE myDate = '2014-06-01'
On my syntax, the average calculation means.. Make zero value to null.
My question is, How if all values are zero...?
Thank you.
Then you get NULL.
If you want zero instead, use COALESCE:
COALESCE( AVG(CASE myField1 WHEN 0 THEN NULL ELSE myField1 END) , 0)
Average will not use nullvalues to calculate an average value
IsNull or Coalesce can be used to change null values to different values.
This script will change 0 to null and take the average value:
SELECT IsNull(AVG(NullIf(val,0)), 0)
FROM
(Values(5),(7),(0)) tbl(val)
Since 0 is excluded the result is 6
You could also do this:
SELECT myDate, COALESCE(AVG(myField1), 0) AS avgmyField1
FROM myTable WHERE myDate = '2014-06-01' and myField1 <> 0