Decimal Overflow in DB2 - db2

I am doing the below SQL in DB2V10.
select
SUM (ORD_QTY * IFNULL(SELL_AMT,0) * IFNULL(WGT_QTY,0))
INTO :WS-VAR FROM TABA with ur;
ORD_QTY => INTEGER
SELL_AMT => DECIMAL(13,4)
WGT_QTY => DECIMAL(11,4)
WS-VAR => PIC S9(13)V9(4) USAGE COMP-3.
I am getting +802 DECIMAL OVERFLOW error.
I am not understanding why exactly I am getting decimal overflow here. Can someone explain me please!

According to the numeric result rules, the resulting precision of SUM (ORD_QTY * IFNULL(SELL_AMT,0) * IFNULL(WGT_QTY,0)) is DECIMAL(15,4), which can hold a value up to the 1011 range.
At the same time, the actual result could be in the range of up to 1010 * 109 * 107, which adds up to 1026.

Related

Cast integer to decimal in DQL

I use Doctrine with a Postgres database and want to update the integer field "voting".
It's a procentual value, saved as integer between 0 and 100, based on the two integer fields "voteCountPro" and "voteCount".
I have to cast one of the integers to a decimal value. (See: Division ( / ) not giving my answer in postgresql)
This doesn't work in DQL and fails with the message:
[Syntax Error] line 0, col 363: Error: Expected Doctrine\ORM\Query\Lexer::T_CLOSE_PARENTHESIS, got ':'
UPDATE statement s
SET s.voting = (s.voteCountPro::decimal / s.voteCount) * 100
WHERE s.id = :id
How can I set the value?
Install https://github.com/oroinc/doctrine-extensions, register the CAST function and write:
UPDATE statement s
SET s.voting = (CAST(s.voteCountPro as decimal) / s.voteCount) * 100
WHERE s.id = :id

Correct My DB2 Query that I am Getting Error

I am using below DB2 query to get the Specific Length of Character
from CLASSIFICATION Coulmn with Condition 0 before the '\', but I am getting error.
select SERVICE_REQUEST,
(case when
(SUBSTR(CLASSIFICATION,LOCATE('\',CLASSIFICATION)-2,1))='0' then
RIGHT(CLASSIFICATION,LENGTH(CLASSIFICATION)-LOCATE('\',CLASSIFICATION))
ELSE CLASSIFICATION
end)
as CLASSIFICATION2
from REPORTDB3.MAXIMO_INDIA_SR_MONTHLY_REPORT where length(SERVICE_REQUEST)=7
ERROR:
An error occurred while processing the results. -
The statement was not executed because a numeric argument of a scalar function is out of range.. SQLCODE=-138, SQLSTATE=22011, DRIVER=4.19.56
Can you please Help me on this.
Regards,
Sambit
Already Gone to Stackoverflow for the answers
I believe you should care about the situations, when the CLASSIFICATION column data have the following problems:
- No \ characters at all
- \ character in the 1-st 2 positions
Your query passes negative 2-nd parameter to the SUBSTR function in these cases, which is not allowed.
with REPORTDB3_MAXIMO_INDIA_SR_MONTHLY_REPORT(CLASSIFICATION, SERVICE_REQUEST) as (
values
('ab0c|def', '1234567')
, ('\def', '1234567')
, ('a\def', '1234567')
, ('ab0c\def', '1234567')
)
select SERVICE_REQUEST, CLASSIFICATION,
case SUBSTR(CLASSIFICATION, case when pos>2 then pos end -2, 1)
when '0' then SUBSTR(CLASSIFICATION, pos+1)
else CLASSIFICATION
end as CLASSIFICATION2
from (
select SERVICE_REQUEST, CLASSIFICATION, LOCATE('\', CLASSIFICATION) as pos
from REPORTDB3_MAXIMO_INDIA_SR_MONTHLY_REPORT
where length(SERVICE_REQUEST)=7
)

How to select float values by mantissa length?

I have a column with double precision values. I am trying to select only those with precision greater than a tenth (e.g., 24.13, 1.347, etc.).
I know I can convert the float to a string and query based on string length using the following:
select * from schema.table where char_length(to_char(float_column, 'FM999999999D999999999')) > 3;
This will return all the rows with more than 1 decimal place if the integer portion of the number is single digit (eg., it will return 24.1).
How can I select any float value that has a mitissa length greater than one?
Use split_part():
with my_table(float_column) as (
values
(24.13::float), (1.347), (12345), (.1)
)
select float_column, split_part(float_column::text, '.', 2)
from my_table;
float_column | split_part
--------------+------------
24.13 | 13
1.347 | 347
12345 |
0.1 | 1
(4 rows)
So your query may look like this:
select *
from my_table
where length(split_part(float_column::text, '.', 2)) > 1;
float_column
--------------
24.13
1.347
(2 rows)
If you stored the value as numeric (fixed point versus floating point), then you could simply do:
where floor(col * 100) <> floor(col * 10) * 10
Unfortunately, there are edge cases where this logic doesn't work for floating point numbers, because you can get something like 21.99999999997.
look for rounding errors:
where round(float_column,1) <> round(float_column,5)

Show Only 2 Decimal Places in SQL Server

I've got some columns that are stored as an INT value that I am doing some addition and division on and I would like to display the results by limiting the digits after the decimal to 2. I've tried different combinations of DECIMAL / NUMERIC / ROUND but I can't get the solution.
Could anyone offer any advice on how to get the desired solution?
Query:
SELECT cc.code AS [CountyID], RTRIM(LTRIM(cc.[description])) AS [CountyName],
SUM(ISNULL(ps.push_count,0)) AS [CountyPushCounts],
SUM(ISNULL(ps.push_unique_count,0)) AS [UniquePushCount],
SUM(ISNULL(ps.error_count,0)) AS [PushErrorCount],
SUM(ISNULL(ps.warning_count,0)) AS [PushWarningCount],
(CAST(SUM(ISNULL(ps.push_unique_count,0)) AS DECIMAL(15,2)) / CAST(SUM(ISNULL(ps.push_count,0)) AS DECIMAL(15,2)) * 100.0) AS [Unique Push Per Day] ,
((CAST(SUM(ISNULL(ps.error_count,0)) AS DECIMAL(15,2)) + CAST(SUM(ISNULL(ps.warning_count,0)) AS DECIMAL(15,2))) / CAST(SUM(ISNULL(ps.push_count,0)) AS DECIMAL(15,2)) * 100.0) AS [Data Error Rate]
FROM dbo.push_stats AS [ps]
INNER JOIN CCIS.dbo.county_codes AS [cc] ON ps.county_code = cc.code
WHERE DATEPART(YEAR,ps.ldstat_date) = 2017
AND DATEPART(MONTH,ps.ldstat_date) = 3
GROUP BY cc.code, cc.[description]
ORDER BY cc.[description];
And my data set looks as follows:
CountyID CountyName PushCounts UniquePushCount PushErrorCount PushWarningCount [Unique Push Per Day] [Data Error Rate]
1 ALACHUA 210422 77046 0 39 36.61499273 0.018534184
2 BAKER 8099 5306 0 71 65.51426102 0.876651438
3 BAY 3178214 434893 117 2793 13.68356568 0.091560857
4 BRADFORD 17654 12119 0 131 68.64733205 0.742041464
I think this will do it:
SELECT cc.code AS [CountyID], RTRIM(LTRIM(cc.[description])) AS [CountyName],
SUM(ISNULL(ps.push_count,0)) AS [CountyPushCounts],
SUM(ISNULL(ps.push_unique_count,0)) AS [UniquePushCount],
SUM(ISNULL(ps.error_count,0)) AS [PushErrorCount],
SUM(ISNULL(ps.warning_count,0)) AS [PushWarningCount],
CAST((SUM(ISNULL(ps.push_unique_count,0)) * 100.00) / SUM(ISNULL(ps.push_count,0)) AS DECIMAL(15,2)) AS [Unique Push Per Day] ,
CAST((SUM(ISNULL(ps.error_count,0)) + SUM(ISNULL(ps.warning_count,0)) * 100.00) / SUM(ISNULL(ps.push_count,0)) AS DECIMAL(15,2)) AS [Data Error Rate]
FROM dbo.push_stats AS [ps]
INNER JOIN CCIS.dbo.county_codes AS [cc] ON ps.county_code = cc.code
WHERE DATEPART(YEAR,ps.ldstat_date) = 2017
AND DATEPART(MONTH,ps.ldstat_date) = 3
GROUP BY cc.code, cc.[description]
ORDER BY cc.[description];
There are two main points here:
With the division operation, get at least one term to a floating point type of some kind before the division happens, so that it doesn't do integer division and truncate the decimal portion of the result. You're okay as long as either term is a floating point type of some kind, and you can accomplish this simply by moving the * 100.00 earlier.
You want to allow much greater than 2 decimal places for the internal calculations, and only set your output format at the very end. Rounding or casting to limited types too soon in an expression can change intermediate values in small ways that are exaggerated in the final results. This means you only want one big CAST() operation around the whole set.
You have to cast the final result, not just the individual numerator and denominator
DECLARE #Numerator INTEGER
DECLARE #Denominator INTEGER
SET #Numerator = 10
SET #Denominator = 3;
-- This will produce 3.33333333
SELECT CAST(#Numerator AS DECIMAL(5,2))/CAST(#Denominator AS DECIMAL(5,2))
-- This will give you 3.33
SELECT CAST(
CAST(#Numerator AS DECIMAL(5,2))
/CAST(#Denominator AS DECIMAL(5,2))
AS DECIMAL(5,2))

Removing decimal places

I have a set of decimal values, but I need to remove the values after the decimal if they are zero.
17.00
23.50
100.00
512.79
become
17
23.50
100
512.79
Currently, I convert to a string and replace out the trailing .00 - Is there a better method?
REPLACE(CAST(amount as varchar(15)), '.00', '')
This sounds like it is purely a data presentation problem. As such you should let the receiving application or reporting software take care of the formatting.
You could try converting the .00s to datatype int. That would truncate the decimals. However, as all the values appear in one column they will have to have the same type. Making everything an int would ruin your rows with actual decimal places.
As a SQL solution to a presentation problem, I think what you have is OK.
I would advice you to compare the raw decimal value with itself floored. Example code:
declare
#Val1 decimal(9,2) = 17.00,
#Val2 decimal(9,2) = 23.50;
select
case when FLOOR ( #Val1 ) = #Val1
then cast( cast(#Val1 as int) as varchar)
else cast(#Val1 as varchar) end,
case when FLOOR ( #Val2 ) = #Val2
then cast( cast(#Val2 as int) as varchar)
else cast(#Val2 as varchar) end
-------------
17 | 23.50