Can a format value "divide" a number in PostgreSQL? - sql

One of the columns of my table has values that can typically range from 3500 to 8 million. Is it possible to specify a format that can divide the number when formatting?
For example, I have the following values:
3500
81000
1678500
Ideally I would like a format value (coming from another config table) that would format the numbers in "thousands" with 1 decimal place:
3.5
81.0
1678.5
But this format value could also be different for other cases, so they could be formatted in millions with two decimal places:
0.00
0.08
1.68
Is this possible, or do I need to divide the numbers myself before applying the formatting?

Is this possible, or do I need to divide the numbers myself before applying the formatting?
You need to do the division. You can use CASE WHEN, by the way, if you aren't having numeric values to track what to divide by:
SELECT tablevalue / CASE divby WHEN 'thousand' THEN 1000 WHEN 'million' THEN 1000000 ELSE 1 END
I presume you'll have some column in your "format" table that also specifies what to divide by..
So you don't want to add a column.. you can store the info in the existing column.. you just have to work more to get it out:
SELECT
TO_CHAR(
somenumber / CASE RIGHT(format, 1) WHEN 'k' THEN 1000 WHEN 'M' THEN 1000000 END,
LEFT(format, -1)
)
So now you can make your format like 99D99k and the k will cause a divide by 1000 and the result is formatted to 99.99, so if you have 1234, format 9.99k you'll get '1.23'out of it.
If you want the [k] at the start it's just some jiggling of the LEFT and RIGHT functions..
TO_CHAR(
somenumber / CASE LEFT(format, 3) WHEN '[k]' THEN 1000 WHEN '[M]' THEN 1000000 END,
RIGHT(format, -3)
)

Related

How to round off numbers in SQL Server database

I have a column (named PercentageDifference) with numbers that have decimal places as shown below:
PercentageDifference
1.886792452830100
2.325581395348800
2.758620689655100
-3.689320388349500
-0.284900284900200
0.400000000000000
I want a query to round off the numbers to the nearest 10 and then leave 2 decimal places.
Here is the output am looking for:
PercentageDifference
1.89
2.33
2.76
-3.69
-0.28
0.40
I have tried to use the ROUND function but its not giving me the expected results:
select round([Percentage Difference], 2, 1) from Table
How can this be achieved?
You need only CAST:
SELECT CAST([Percentage Difference] AS decimal(19,2)) FROM Table;

Calculate percentage between two columns in SQL Query as another column

I have a table with two columns, number of maximum number of places (capacity) and number of places available (availablePlaces)
I want to calculate the availablePlaces as a percentage of the capacity.
availablePlaces capacity
1 20
5 18
4 15
Desired Result:
availablePlaces capacity Percent
1 20 5.0
5 18 27.8
4 15 26.7
Any ideas of a SELECT SQL query that will allow me to do this?
Try this:
SELECT availablePlaces, capacity,
ROUND(availablePlaces * 100.0 / capacity, 1) AS Percent
FROM mytable
You have to multiply by 100.0 instead of 100, so as to avoid integer division. Also, you have to use ROUND to round to the first decimal digit.
Demo here
The following SQL query will do this for you:
SELECT availablePlaces, capacity, (availablePlaces/capacity) as Percent
from table_name;
Why not use a number formatting function such as format_number (or an equivalent one in your database) to format a double as a percentage? This example is generalized. The returned value is a string.
WITH t
AS
(
SELECT count(*) AS num_rows, count(foo) as num_foo
FROM mytable
)
SELECT *, format_number(num_foo/num_rows, '#.#%') AS pct_grade_rows
FROM t
This avoids the use of round and multiplying the numerator by 100.

Insert decimalplaces into number and the round the sum

I'm new to Oracle and coming from MS SQL Server enviroment.
How do I format a column that is of type number(10) so a comma will be inserted before the last two digits, sum the formatted values and then round the sum?
Amount column values
400 (format to 4,00)
4000 (format to 40,00)
40000 (format to 400,00)
400000 (format to 4000,00)
639 (format to 6,39)
Sum of the formatted numbers will in this case be: 4445,39
Round the sum will return: 4445.
The queries I've tried with:
select TO_CHAR((ROUND(SUM(Amount))),'FM9999999G90')
select TO_NUMBER(ROUND((TO_CHAR(SUM(Amount),'FM9999999G90'))), '9999999.99')
Result: 4450.39, but I want it to be rounded to 4450 in this case.
Fiddle
You just need to divide the number by 100, and then ROUND it:
ROUND(SUM(amount)/100)
See this SQL Fiddle for a working demo:

Retrospection on Float, Real and Decimal data types

I'm trying to understand the repercussions of having a column with real data type in a database(Sql Server) table, in my scenario. I have a column in my database with real datatype. The data is static, its always one of the values in range 0.0, 0.1, 0.2.. to 1.0.
Use Case:
I have to Sum up the values in the column and use the sum value in some arithmetic calculations which include financial data.
Concern?:
When I sum up values in the column it gives me result with more decimal places.
Test:
I want sum up the column values and use it in multiplication and division calculations.
I want to repeat #1 for same set of values in a column with decimal and float data types.
Procedure: I have created three different tables with a single column and same set of values but different data types, one with decimal, float and real. And perform the arithmetic calculations on each of them.
CREATE TABLE #tReal(d real);
INSERT INTO #tReal
SELECT 0.1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 0.9 UNION ALL
SELECT 1 UNION ALL
SELECT 0.9 UNION ALL
SELECT 1;
select SUM(d) from #tReal
Expected Result : 5.9
Actual Result : 5.8999999538064
And, If I perform round operation on the sum the result is as expected
declare #sumofd real
select #sumofd = SUM(d) from #tReal
select round(#sumofd , 1)
Result: 5.9
Also, if I update datatype from real to float
CREATE TABLE #tfloat(d float);
INSERT INTO #tfloat
SELECT 0.1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 0.9 UNION ALL
SELECT 1 UNION ALL
SELECT 0.9 UNION ALL
SELECT 1;
select SUM(d) from #tfloat
Expected Result : 5.9
Actual Result : 5.9
And, This is the same case if I update datatype from real to decimal
CREATE TABLE #tDecimal(d DECIMAL(3,2));
INSERT INTO #tDecimal
SELECT 0.1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 0.9 UNION ALL
SELECT 1 UNION ALL
SELECT 0.9 UNION ALL
SELECT 1;
select SUM(d) from #tDecimal
Expected Result : 5.94
Actual Result : 5.94
And, If I perform some basic arithmetic operations on the sum, without rounding, like
declare #sumofdReal real
declare #sumofdFloat float
declare #sumofdDecimal decimal(3,2)
select #sumofdReal = SUM(d) from #tReal
select #sumofdFloat = SUM(d) from #tfloat
select #sumofdDecimal = SUM(d) from #tDecimal
Multiplication:
select #sumofdReal * 2
Result: 11.8
select #sumofdFloat * 2
Result: 11.8
select #sumofdDecimal * 2
Result: 11.88
Division:
select #sumofdReal / 2
Result: 2.95
select #sumofdFloat / 2
Result: 2.95
select #sumofdDecimal / 2
Result: 2.97000
Drop Tables:
drop table #tReal
drop table #tfloat
drop table #tDecimal
Following are my questions
In my scenario, having a datatype as real will have any repercussions?
If #1 is yes, what kind of repercussions? Do I have to change datatype to float or decimal? Why?
If #1 is No, Why? Please explain?
Is there a point to which float and real types can produce exact result and anything beyond it rounding errors will show up?
real in SQL Server is a synonym for float(24), which takes 4 bytes and up to 7 digits of precision.
float by itself is the same as float(53) which is also the same as double which takes up 8 bytes and has up to 15 digits of precision.
In my scenario, having a datatype as real will have any repercussions?
Possibly. decimal, float, and real have different characteristics and are not fully interchangeable. If you want to maintain the exact decimal representation, use the decimal datatype with the appropriate scale and precision. If your numbers represent imprecise data (such as temperature, height, time, or other "natural" measurements that cannot be measured without some imprecision) and want faster mathematical operations then use float (or real if you don;t need more than 7 digits of precision.
When I sum up values in the column it gives me result with more decimal places.
When you add floating point numbers, SQL determines how big the result can be and will use the appropriate data type. When you add two reals, the result could have more than 7 digits of precision, so it may use float as the resulting data type.
Do I have to change datatype to float or decimal? Why?
Use float if you may have more than 7 digits of precision, don't need absolute precision from a decimal standpoint, and want to use a floating-point type for faster calculations.
If you want a fixed scale and precision and want to minimize the imprecision involved with floating point numbers use decimal.
Working with floating-point values always has repercussions, because they are not represented exactly and some rounding errors will always occur. You have to be most careful when comparing values with constants, e.g. if (a == 0.0) as this won't always work if 'a' is the result of mathematical operations. Float and Decimal just give you different ranges and precisions.
If you are using these values in financial calculations, then you should always (pretty much) use decimal types, otherwise you will run into issues with floating point rounding at some point. People get very wound up when you start losing pennies.
You may want to read some more on floating point arithmetic here:
http://floating-point-gui.de/
Decimal types will not be subject to these and should be exact.
For an example, you will eventually run into the situation where you try and round a number to 2 DP, e.g. 0.695, which you would expect to round up to 0.70.
DECLARE #x REAL = 0.695
SELECT ROUND(#x, 2)
-- outputs 0.69
DECLARE #y DECIMAL(6,4) = 0.695
SELECT ROUND(#y, 2)
-- outputs 0.7000
This is down to the fact that you cannot accurately represent 0.695 as a floating point number and it is in fact marginally less than 0.695 as saved.

sql where condition for int but column type is Varchar

I have table called Buttons. Buttons table i have column button_number . Table contain more than 100 records. Now i have to select a buttons number between 10 to 50. When i used this following query it's not returning zero row.
select * from Buttons where button_number >= '10' and button_number <='50'
What's the problem in the query. If i use the same query with different column(data type is int) then it's working fine. Is the problem because of the data type of the column? If so what's the fix for this?
Note : button_number column data type is Varchar.
The button_number is varchar and you are trying to do an integer style comparison. You will need to cast the button_number column to an integer.
select * from Buttons where
convert(integer, button_number) >= 10 and convert(integer, button_number) <= 50
Edit
The above query will require a table scan since it needs to convert every button_number to an integer before applying the where clause. This isn't a problem for 100 rows, but would be an issues for large numbers.
As mentioned in Mikael Eriksson's answer, a better alternative would be to change the type of button_number to an integer type (if possible). This would have several advantages:
There would be no chance of entering a non-integer value in the column
You would then be able to apply an integer index to the column. This would greatly improve the speed of your query when the table contains large numbers of rows.
If so what's the fix for this?
The other answers tells you to cast the column to int in the query. That will work for you if you only have integers in the column. If that is the case you should change the data type for column button_number to int so you don't risk having a character value in there that will break your query.
modify your query like below
select * from Buttons where cast(button_number as int) >= 10 and cast(button_number as int) <=50
but make sure that all the values of column "button_number" dont have any charcters
Depending on your DB type and your version, but in MySQL you might need to use SIGNED or UNSIGNED as your datatype:
SELECT * FROM Buttons
WHERE CONVERT(SIGNED, button_number) >= 10
AND CONVERT(SIGNED, button_number) <= 50
In postgreSQL database you can convert like this :
select * from Buttons where
button_number::int >= 10 and convert(integer, button_number) <= 50