decimal point issue once again - sql

The first line of code displays to 2 decimal points
The second line displays to 3 decimal points
SUM(CONVERT(DECIMAL(8,2),[can]/1.2)) + SUM(CONVERT(DECIMAL(8,2),[carton]/1.2)) AS [N],
(SUM(CONVERT(DECIMAL(8,2),[can]/1.2)) + SUM(CONVERT(DECIMAL(8,2),[carton]/1.2)))*0.2 AS [V]
Can someone please tell me how to get the second line to show 2 decimal points

If you want to control the display, the do the cast to decimal after the calculation:
CONVERT(DECIMAL(8, 2), SUM([can]/1.2)) + SUM([carton]/1.2)) AS [N],
You can do the conversion before, if you have a need to represent the some intermediate value as a decimal. Do note, though, that SQL Server has quite arcane rules for the precision and scale of intermediate and final results when doing decimal arithmetic.

Just cast the result to a 2 decimal place decimal:
select --just added to make the example runnable
SUM(CONVERT(DECIMAL(8,2),[can]/1.2)) + SUM(CONVERT(DECIMAL(8,2),[carton]/1.2)) AS [N],
CONVERT(DECIMAL(8,2), --add this line
(SUM(CONVERT(DECIMAL(8,2),[can]/1.2)) + SUM(CONVERT(DECIMAL(8,2),[carton]/1.2)))*0.2
) --and an additional close bracket
AS [V]
from (select 1.0 [can], 1.0 [carton] union all select 2.0, 3.0) x --just added to make the example runnable
The reason you're seeing 3 decimal places is because that's what the result of the calculation is; and when working with decimals SQL will output a decimal of the appropriate precision and scale to hold that result, unless you cast/convert it to something specific.

You convert to 2 decimals using CONVERT...
SELECT
SUM(CONVERT(decimal(8, 2), [can] / 1.2)) + SUM(CONVERT(decimal(8, 2), [carton] / 1.2)) AS [N],
CONVERT(decimal(8, 2), ((SUM(CONVERT(decimal(8, 2), [can] / 1.2)) + SUM(CONVERT(decimal(8, 2), [carton] / 1.2))) * 0.2)) AS [V]

Related

How to format my result for 2 decimals digits after comma

I'm kind new to SQL world and just started doing queries.
In this case, I'm calculating how much % a number represents of that other number.
This is how I'm doing:
Percentage = ROUND(((NULLIF(SUM(value_1), 0)) / NULLIF(SUM(value_2),0) * 100), 2),
Even if I use ROUND(), the results still the same, they will give me 6 digits after comma:
100.020000
56.800000
-33.330000
100.000000
42.490000
Is there any way to format these numbers with just 2 digits after comma?
Thank you!
Assuming you use sql server, you can convert your result :
Percentage = Convert(numeric(10, 2), ROUND(((NULLIF(SUM(value_1), 0)) / NULLIF(SUM(value_2),0) * 100), 2))
Or Cast it :
Percentage = Cast(ROUND(((NULLIF(SUM(value_1), 0)) / NULLIF(SUM(value_2),0) * 100), 2) AS numeric(10, 2))

SQL: Cannot convert nvarchar to numeric in complex query

I need to get the nearest airport in my database table from the current users position. I found this formula: https://de.scribd.com/presentation/2569355/Geo-Distance-Search-with-MySQL#page=7
So there are a few differences between the formula described in the link above and my current situation: The example was in MySQL, I'm using MS SQL (not a problem, I guess). lat and lon are considered to be database columns with numeric data type, but for some reason the database table was created with two corresponding columns of type varchar.
My problem is: When I want to use an ORDER BY clause, it throws Error converting data type nvarchar to numeric, without it, it works. I did some research on what rubbish was inserted as string and migrated it so that I just have some empty values.
I can't take all because I only need one. But if I do TOP 1 without ORDER BY I don't get any airport rather than the nearest airport. Does anyone know how to fix the query?
Thanks in advance!
SELECT TOP 1
temp.Distance
FROM (
SELECT
(
3956 * 2 * ASIN(
SQRT(
POWER(
SIN((53.6349994 - abs(CAST(latitude_deg AS numeric))) * pi() / 180 / 2), 2) + COS(53.6349994 * pi()/180) * COS(abs(CAST(latitude_deg AS numeric)) * pi()/180) * POWER(SIN((10.0117336 - CAST(longitude_deg AS numeric)) * pi()/180 / 2), 2) ))) AS Distance
FROM Airport_Airports
WHERE
isnumeric(longitude_deg) = 1 AND isnumeric(latitude_deg) = 1 AND
longitude_deg LIKE '%[^0-9.]%' AND latitude_deg LIKE '%[^0-9.]%'
) AS temp
WHERE
temp.Distance < 50000
Order BY
temp.Distance
First, this logic doesn't make sense:
WHERE isnumeric(longitude_deg) = 1 AND
isnumeric(latitude_deg) = 1 AND
longitude_deg LIKE '%[^0-9.]%' AND
latitude_deg LIKE '%[^0-9.]%'
The like is looking for non-numeric characters. I think you intend:
WHERE isnumeric(longitude_deg) = 1 AND
isnumeric(latitude_deg) = 1 AND
longitude_deg NOT LIKE '%[^0-9.]%' AND
latitude_deg NOT LIKE '%[^0-9.]%'
This ensures that the values are numeric.
The solution to your problem -- at least in SQL Server 2012+ -- is to use try_convert() or try_cast():
(3956 * 2 * ASIN(
SQRT(
POWER(
SIN((53.6349994 - abs(try_convert(numeric, latitude_deg))) * pi() / 180 / 2), 2) + COS(53.6349994 * pi()/180) * COS(abs(try_convert(numeric, latitude_deg)) * pi()/180) * POWER(SIN((10.0117336 - try_convert(numeric, longitude_deg)) * pi()/180 / 2), 2) ))) AS Distance
This will prevent any conversion errors.
You shouldn't use just numeric. Use either a floating point representation or something with decimal places, say numeric(20, 10).
The reason this occurs with the order by is because of the SQL optimizer. You clearly have some lat/long values that do not convert correctly to a numeric. SQL Server allows itself to re-arrange operations, so the conversion might take place before the filtering by the where clause. This is part of the overall query optimization.

MsSQL FLOOR CEILING issue? Or is there an explanation about that?

anyone can try this in MsSQL:
select floor(4.7000000000000000000000000000000000000)+0.5
I get this result: 5 (!!) But should be 4.5 !?
Or try again with:
select floor(4.70 * 0.25000 * 0.2440 * 5.6325 * 3.0542 * 2.345 * 2.35 * 3.253 )+0.5
The result is 89!! But should be: 88.5 ?!
Is this an issue? Or is there an explanation about that?
(the same problem with CEILING)
Thank you all!
Per the documentation of FLOOR:
-- Syntax for SQL Server, Azure SQL Data Warehouse, Parallel Data Warehouse
FLOOR ( numeric_expression )
Return Types
Returns the same type as numeric_expression.
The problem with this is that it's not true. It preserves the base type, but in case of a decimal type, the scale is reduced to 0:
SELECT
SQL_VARIANT_PROPERTY(4.00, 'precision') AS [precision]
SQL_VARIANT_PROPERTY(4.00, 'scale') AS scale,
Result: precision 3, scale 2.
SELECT
SQL_VARIANT_PROPERTY(FLOOR(4.00), 'precision') AS [precision],
SQL_VARIANT_PROPERTY(FLOOR(4.00), 'scale') AS scale
Result: precision 3, scale 0. This becomes a problem as soon as your decimal hits the maximum precision:
SELECT
SQL_VARIANT_PROPERTY(4.7000000000000000000000000000000000000, 'precision') AS [precision]
SQL_VARIANT_PROPERTY(4.7000000000000000000000000000000000000, 'scale') AS scale,
Precision 38, scale 37. But FLOOR turns this into precision 38, scale 0, and
SELECT CONVERT(DECIMAL(38, 0), 4) + 0.5
results in 5, per the rules for precision and scale when adding decimals: the result of this should be a decimal(40, 1), but as that exceeds the maximum precision, the scale is reduced to preserve as many digits in front of the period as possible, giving us a decimal(38, 0) again: 5.
Conversely, there's no problem with this:
SELECT 4.0000000000000000000000000000000000000 + 0.5
The result of this is a DECIMAL(38, 37), which can hold 4.5000000000000000000000000000000000000 exactly.
The moral: be aware of this scale-eliminating aspect of FLOOR (and CEILING) and reduce the precision as necessary so the scale doesn't get reduced due to overflow:
SELECT CONVERT(DECIMAL(3, 0), FLOOR(4.70 * 0.25000 * 0.2440 * 5.6325 * 3.0542 * 2.345 * 2.35 * 3.253)) + 0.5
Yields 88.5.

T-SQL - how to round DOWN to nearest .05

The database I am using is SQL Server 2005. I am trying to round values DOWN to the nearest .05 (nickel).
So far I have:
SELECT ROUND(numberToBeRounded / 5, 2) * 5
which almost works - what I need is for the expression, when numberToBeRounded is 1.99, to evaluate to 1.95, not 2.
Specify a non-zero value for a third parameter to truncate instead of round:
SELECT ROUND(numberToBeRounded / 5, 2, 1) * 5
Note: Truncating rounds toward zero, rather than down, but that only makes a difference if you have negative values. To round down even for negative values you can use the floor function, but then you can't specify number of decimals so you need to multiply instead of dividing:
SELECT FLOOR(numberToBeRounded * 20) / 20
If your data type is numeric (ISO decimal) or `money, you can round towards zero quite easily, to any particular "unit", thus:
declare #value money = 123.3499
declare #unit money = 0.05
select value = value ,
rounded_towards_zero = value - ( value % #unit )
from #foo
And it works regardless of the sign of the value itself, though the unit to which you're rounding should be positive.
123.3499 -> 123.3000
-123.3499 -> -123.3000

SQLServer CAST and divide 2 decimal numbers, followed by multiplication gives too many decimal places

I'm working in SQL Server 2008. I have an alias column that I'm creating via the following formula:
col1 / col2 * some_number
col1 and col2 are nvarchars in my table, but they're really integers. some_number is an integer. If I blindly do col1 / col2, I will get 0 for most. So, I need to cast them as decimals. I want there to be a maximum of 2 decimal places after the decimal point. Here is what I have currently:
CAST(col1 AS DECIMAL(10,2)) / CAST(col2 AS DECIMAL(10,2)) * 100
However, this returns far more decimal places than just 2. How do I fix my code to return just 2 decimal places?
According to the documents the scale of the result is given by:
s2 = max(6, s1 + p2 + 1)
where p2 represents the precision of the numerator and s2 represents scale of the denominator
So when dividing one DECIMAL(10, 2) by another you can substitute in values:
s2 = max(6, 2 + 10 + 1) = 13
Which is corroborated with a simple example:
SELECT CAST(1 AS DECIMAL(10,2)) / CAST(1 AS DECIMAL(10,2))
= 1.0000000000000 -- 13 decimal points
You need to use another cast on your result to reduce the scale:
SELECT CAST(CAST(col1 AS DECIMAL(10,2)) / CAST(col2 AS DECIMAL(10,2)) * 100 AS DECIMAL(10, 2))
I'd also suggest if the data type of you column is nvarchar, "but they're really integers" that you just bite the bullet and alter the column data type.