Oracle Number Issue - sql

Good Day,
I have an issue I could use your help with.
A customer would like invoice amounts displayed as follows:
Example Invoice Amounts
-405.12 to be shown as 000000040512
&
-400.00 to be shown as 000000040000
The following query works fine for the 405.12 amount, but for the 400.00 amount it drops the two zeros on the right side
LPAD(REPLACE((invoiceamt*-1),'.',''),12,0)
How may I solve this issue?
Thank You
Aaron

I suggest
to_Char(abs(invoiceamt) * 100, '000000000000')
where
abs - absolute value - get rid of sign (-)
* 100 - removing decimal point
to_Char - final formatting (12 mandatory digits)

Forget the REPLACE, just multiply invoiceamt by -100 and then LPAD to the required length.

Another question has reminded me of the existence of the V format model element:
Returns a value multiplied by 10^n (and if necessary, round it up), where n is the number of 9's after the V.
But you can use zeros instead of 9s to keep leading zeros, and add FM to remove the leading space (which is there for a - symbol for negative values - which you won't have). So you can also do:
with t (n) as (
select -405.12 from dual
union all select -400 from dual
)
select n, to_char(abs(n), 'FM0000000000V00') as result
from t;
N RESULT
---------- -------------
-405.12 000000040512
-400 000000040000

Related

How to calculate the ratio of this column with 2 rows

I am very new to SQL and am having difficulty figuring out hot to divide row1 (101) by row2 (576).
COUNT
101
576
I want the output to be a single value expressed to 2 decimal places.
Any tips?
Thanks for the help
For two rows, it's easy.
If you have a big input table, and you want to divide the first row by the second, the third row by the fourth, etc, then you need an ordering column to save yourself.
So, with a two-row table (remember, tables are never ordered), you just rely on the fact that you divide the smaller number by the bigger number.
Here goes:
WITH
-- your input ...
input(counter) AS ( -- count is reserved word, use another name ...
SELECT 101
UNION ALL SELECT 576
)
-- cheat and just divide the smaller by the bigger
-- as "#Gordon Linoff" suggests
-- force a float division by adding a non-integer operand
-- and hard-cast it to DECIMAL(5,2)
SELECT
CAST(
MIN(counter) * 1.00 / MAX(counter)
AS DECIMAL(5,2)
) AS result
FROM input;
-- out result
-- out ----------
-- out 0.18
If, however, you have many rows, and you always need to divide the first row by the second, the third row by the fourth, that is, each odd row in the order by the next even row in the order, then you need an ordering column.
Is your problem just what you suggested, or is there more to it?
There is no such thing as row "1" or "2" in a table. Tables represent unordered sets, so without a column specifying the ordering, there is no first or second row.
You can use aggregation to divide by min by the max:
select min(count) * 1.0 / max(count)
from t;
Note the * 1.0. Postgres does integer division, so you want to convert to something with a decimal point.

Storing extremely small values in Amazon Redshift

I am creating a table in Amazon Redshift using the following command:
CREATE TABLE asmt.incorrect_question_pairs_unique
AS
SELECT question1,
question2,
occurrences,
occurrences / (SUM(occurrences)::FLOAT) OVER () AS prob_q1_q2
FROM (SELECT question1,
question2,
SUM(occurrences) AS occurrences
FROM asmt.incorrect_question_pairs
GROUP BY question1,
question2
HAVING SUM(occurrences) >= 50)
I also tried an alternate:
CREATE TABLE asmt.incorrect_question_pairs_unique
AS
SELECT question1,
question2,
occurrences,
occurrences::float / SUM(occurrences) OVER () AS prob_q1_q2
FROM (SELECT question1,
question2,
SUM(occurrences) AS occurrences
FROM asmt.incorrect_question_pairs
GROUP BY question1,
question2
HAVING SUM(occurrences) >= 50)
I'd like the column prob_q1_q2 to be a float column, which is why I am converting the denominator/numerator to float. But in the resulting table, I get all zeros in that column.
I would like to point out that the SUM(occurrences) would amount to about 10 Billion, so the column prob_q1_q2 will contain extremely small values. Is there a way to store such small values in Amazon Redshift?
How do I make sure that all the values in the column are non-zero float?
Any help would be appreciated.
METHOD 1 - I have had the same problem! In my case it was million of rows so I Multiplied the result by 10000. whenever I wanted to select values from that column I would divide by 10000 in the select statement to make it even. I know its not the perfect solution but works for me.
METHOD 2 - I created a sample table with Numeric(12,6) datatype and when I imported the result set similar to yours, I can see the float values upto 6 decimal precision.
I guess, the conversion does not work when you use create table AS command, you need to create the table specifying the datatype which enforces the result set to be stored to a certain precision level. Its odd! how the same select returns 0.00 but when inserted into table with enforced column, it returns 0.00333.
If I’ve made a bad assumption please comment and I’ll refocus my answer.
Patthebug,
You might be getting a way too low number which cannot be stored in the FLOAT type of Amazon Redshift. Try using DECIMAL instead, there is no way it cannot store your value it's a 128 bit variable.
The way it works is the following, if the value if too big or in your case too small and it exceeds the max/min value of your type the last digits are trimmed and then the new (trimmed) value is stored in the variable/column of your type.
When it is trimming a big value you lose almost nothing lets say you are trimming 20 cents out of 20 billion dollars, you wont be hurt much. But in your case when the number is too small you can loose everything when it trims the last digits to fit in the type
(f.e. A type can store up to 5 digits and you want to store a value of 0.000009 in a variable/column of this type. Your value cannot be fit in the type so its trimmed from the last 2 digits so it can be fit and you receive a new value of 0.0000 )
So if you followed my thought just changing the ::float to ::decimal should fix your issue.
P.S. decimal might require specifying it's size f.e. decimal(127,100)
Try:
select cast(num1 as float) / cast(num2 as float);
This will give you results upto 2 decimal places (by default), but takes up some of your processing time. Doing anything else will round-off the decimal part.
You can have up to 38 digits in a DECIMAL/NUMERIC column with of 37 digits of scale.
CREATE TEMP TABLE precision_test (test NUMERIC(38,37)) DISTSTYLE ALL
;
INSERT INTO precision_test
SELECT CAST( 0.0000000000000000000000000000000000001 AS NUMERIC(38,37)) test
;
SELECT * FROM precision_test
;
--Returns 0.0000000000000000000000000000000000001

Multiplying a varchar and a decimal field together

I have a table that contains the field as:
doses_given decimal(9,2)
that I want to multiply against this field:
drug_units_per_dose varchar(255)
So I did something like this:
CAST(ppr.drug_units_per_dose as decimal(9,2)) * doses_given dosesGiven,
However, looking at the data, I notice some odd characters:
select distinct(drug_units_per_dose) from patient_prescr
NULL
1
1-2
1-4
1.5
1/2
1/4
10
12
15
1½
2
2-3
2.5
20
2½
3
3-4
30
4
5
6
7
8
½
As you can see, I am getting some characters that cannot be CAST to decimal. On the web page these fields are interpreted as a small 1/2 symbol:
Is there anyway to replace the ½ field with a .5 to accurately complete the multiplication?
The 1/2 symbol is ascii character 189, so to replace:
CAST(REPLACE(ppr.drug_units_per_dose,char(189),'.5') as decimal(9,2)) * doses_given dosesGiven
You have a rather nasty problem. You have a field drug_units_per_dose that a normal human being would consider to be an integer or floating point number. Clearly, the designers of your database are super-normal people, and they understand a much wider range of options for this concept.
I say that partly tongue in cheek, but to make an important point. The column in the database does not represent a number, at least not in all cases. I would suggest that you have a translation table for drug_units_per_dose. It would have columns such as:
1 1
1/2 0.5
3-4 ??
I realize that you will have hundreds of rows, and a lot of them will look redundant because they will be "50,50" and "100,100". However, if you want to keep control of the business logic for turning these strings into a number, then a lookup table seems like the sanest approach.
CAST(prod.em_amccom_comset AS int) * invline.qtyinvoiced AS setcredits
syntax - CAST(char_value as int) * integer_value as alias_name

Round up value to nearest whole number in SQL UPDATE

I'm running SQL that needs rounding up the value to the nearest whole number.
What I need is 45.01 rounds up to 46. Also 45.49 rounds to 46. And 45.99 rounds up to 46, too. I want everything up one whole digit.
How do I achieve this in an UPDATE statement like the following?
Update product SET price=Round
You could use the ceiling function; this portion of SQL code :
select ceiling(45.01), ceiling(45.49), ceiling(45.99);
will get you "46" each time.
For your update, so, I'd say :
Update product SET price = ceiling(45.01)
BTW : On MySQL, ceil is an alias to ceiling ; not sure about other DB systems, so you might have to use one or the other, depending on the DB you are using...
Quoting the documentation :
CEILING(X)
Returns the smallest integer value not
less than X.
And the given example :
mysql> SELECT CEILING(1.23);
-> 2
mysql> SELECT CEILING(-1.23);
-> -1
Try ceiling...
SELECT Ceiling(45.01), Ceiling(45.49), Ceiling(45.99)
http://en.wikipedia.org/wiki/Floor_and_ceiling_functions
For MS SQL CEILING(your number) will round it up.
FLOOR(your number) will round it down
Combine round and ceiling to get a proper round up.
select ceiling(round(984.375000), 0)) => 984
while
select round(984.375000, 0) => 984.000000
and
select ceil (984.375000) => 985
Ceiling is the command you want to use.
Unlike Round, Ceiling only takes one parameter (the value you wish to round up), therefore if you want to round to a decimal place, you will need to multiply the number by that many decimal places first and divide afterwards.
Example.
I want to round up 1.2345 to 2 decimal places.
CEILING(1.2345*100)/100 AS Cost
If you want to round off then use the round function. Use ceiling function when you want to get the smallest integer just greater than your argument.
For ex: select round(843.4923423423,0) from dual gives you 843 and
select round(843.6923423423,0) from
dual gives you 844
This depends on the database server, but it is often called something like CEIL or CEILING. For example, in MySQL...
mysql> select ceil(10.5);
+------------+
| ceil(10.5) |
+------------+
| 11 |
+------------+
You can then do UPDATE PRODUCT SET price=CEIL(some_other_field);

How do I calculate percentages with decimals in SQL?

How can i convert this to a decimal in SQL? Below is the equation and i get the answer as 78 (integer) but the real answer is 78.6 (with a decimal) so i need to show this as otherwise the report won't tally up to 100%
(100 * [TotalVisit1]/[TotalVisits]) AS Visit1percent
Try This:
(100.0 * [TotalVisit1]/[TotalVisits]) AS Visit1percent
convert(decimal(5,2),(100 * convert(float,[TotalVisit1])/convert(float,[TotalVisits]))) AS Visit1percent
Ugly, but it works.
CAST(ROUND([TotalVisit1]*100.0/[TotalVisits],2)as decimal(5,2)) as Percentage
Not ugly and work better and fast , enjoy it!
At least in MySQL (if it helps), if you want to use float numbers you had to use a type float field, not the regular int fields.
Just add a decimal to the 100
(100.0 * [TotalVisit1]/[TotalVisits]) AS Visit1percent
this forces all processing to happen in floats... if you want the final output as text, and truncated for display to only one decimal place, use Str function
Str( 100.0 * [TotalVisit1]/[TotalVisits], 4, 1 ) AS Visit1percent
This works perfectly for me:
CAST((1.0 * SUM(ColumnA) /COUNT(ColumnB)) as decimal(5,2))
Hope it helps someone out there in the world.
Its probably overkill to do this, but you may wish to consider casting all values to floats to ensure accuracy at all phases.
(100.0 * ( [TotalVisit1]+0.0 )/([TotalVisits]+0.0) ) as Visit1percent
Note, you really need to put code in here for the case that TotalVisits == 0 or you will get a division by 0 answer.
SELECT(ROUND(CAST(TotalVisit1 AS DECIMAL)/TotalVisits,1)) AS 'Visit1percent'
This will return a decimal and the ROUND will round it to one digit. So in your case you would get 76.6. If you don't want any digits change the 1 to 0 and if you want two digits change it to 2.
Try with this, no round and str or Over(). i found this as a simpler way to do it.
cast((count(TotalVisit1) * 100.0) /TotalVisits as numeric(5,3)) as [Visit1percent]
You can change the number of decimal points as you wish to
e.g. numeric(5,2) or numeric(5,4)
This might not address you issue directly, but when you round a set of numbers for display you're never guaranteed to get numbers that add to 100 unless you take special precautions. For example, rounding 33.33333, 33.33333 and 33.33333 is going to leave you one short on the sum, so the logical thing to do is to modify the percentage for the largest value in the set to take account of any difference.
Here's a way of doing that in Oracle SQL using analytic functions and a subquery factoring (WITH) clause to generate sample data.
with data as (select 25 num from dual union all
select 25 from dual union all
select 25 from dual)
select num,
case
when rnk = 1
then 100 - sum(pct) over (order by rnk desc
rows between unbounded preceding
and 1 preceding)
else pct
end pct
from
(
select num,
round(100*ratio_to_report(num) over ()) pct,
row_number() over (order by num desc) rnk
from data
)
/
NUM PCT
---------------------- ----------------------
25 33
25 33
25 34
In ms Access You can use the SQL function ROUND(number, number of decimals), It will round the number to the given number of decimals:
ROUND((100 * [TotalVisit1]/[TotalVisits]),1) AS Visit1percent