return datediff as decimal/percent - vb.net

i am currently writing a scalar valued function and i'm having a few issue with the returned result.
i have narrowed the problem down to a calulation that convert the difference between two dates as a percentage/decimal. no matter what i try the return value is always a whole number
set #earnedpremium = (#premium * #pretripearnings) + ((#premium - (#premium * #pretripearnings)) * cast((datediff(day, #outdate, #experiencedate) / datediff(day, #outdate, #returndate))as decimal(5,2)))
the cast section needs to return the percentage, i know the rest is working fine through some elimination and testing.
can someone please help me figure out what im doing wrong??

It's because DATEDIFF returns an INTEGER and so you need to cast both parts of that operation to DECIMAL:
set #earnedpremium = (#premium * #pretripearnings) + ((#premium - (#premium * #pretripearnings))
* (CAST(datediff(day, #outdate, #experiencedate) AS DECIMAL(5,2)) /
CAST(datediff(day, #outdate, #returndate) AS DECIMAL(5,2)))

Related

Teradata Arithmetic operations

In Teradata when computing a percentage (see example below), I get 0 as an answer because Terada rounds results based on the number of decimal places the number have. to my knowledge I have found 2 possible solution to avoid the zero value return.
1- define the decimal number in table with a larger scale value. e.g decimal(18,4) instead of decimal(18,2)
2- cast the first arithmetic operation that occurs to a decimal number with a larger scale value. e.g. select (cast(2.0 as decimal(10,6)) / 10.0) * 100;
has anyone encounter this problem before and what is the solution you went with to solve the problem? thank you in advance.
these are the actual values and the correct answer should be 0.25
select ((28.97 + 28.97) / (11586.87 + 11586.87)) * 100
,(cast((28.97 + 28.97) as decimal(20,4)) / (11586.87 + 11586.87)) * 100
,((cast(28.97 as decimal(18,4)) + 28.97) / (11586.87 + 11586.87))
,(100 * (28.97 + 28.97) / (11586.87 + 11586.87))
,(28.97 + 28.97) , (11586.87 + 11586.87);

SQL Cast to show decimals

I have the following statement within my select clause;
(([Complt_Emp] + [No_Non_Complt_Emp])/ [No_of_Emp]) as Total_Completed
How do I implement CAST "cast(your_float_column as decimal(10,2))" ? I want my column Total_Completed to show 2 decimal places
I cannot seem to get the correct syntax!
Thank you
the result of the calculation depends of the used columns type.
If you divide int columns, you get int result : 1 / 6 = 0
when you convert each values to decimal the result is: 1 / 6 = 0.1666666666666
Now you want 2 decimal result,so you have to convert/ round the previous result to get the expected value
See fiddle for some example of divide and cast / round : http://sqlfiddle.com/#!18/51785/5
An easy trick can be to use :
round ( 1.0 * ( [Complt_Emp] + [No_Non_Complt_Emp] ) / [No_of_Emp] , 2 )
Cast each expression seperately
CAST(([Complt_Emp] + [No_Non_Complt_Emp]) as decimal(10,2)) /
CAST([No_of_Emp] as decimal(10,2)) as Total_Completed
I suspect all your values are INT. An int divided by an int will return an int.
(([Complt_Emp] + [No_Non_Complt_Emp])/ cast([No_of_Emp] as decimal(10,2)) as Total_Completed
Try this
cast((([Complt_Emp] + [No_Non_Complt_Emp])/ [No_of_Emp]) as decimal(10,2)) as Total_Completed

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.

how to handle divide by zero error in sql

cast(CAST(countAta AS float)
/ CAST(DATEDIFF(day,#searchDate,#EndDate) AS float) as decimal(16,2)
)
You can avoid such situations by setting the following parameters before your query and it should work just fine.
SET ARITHABORT OFF
SET ANSI_WARNINGS OFF
This would return a NULL when you do something like this: 123 / 0
The important point is to set these properties back ON once you are done with such operations. This particularly helps when you have complex queries in your Stored procedure and you don't want to end up writing more and more CASE statements to handle such a situation.
You should always use TRY-CATCH block and use the built-in error handling functions provided by SQL. Also, you can handle it in another way --
SELECT CASE
WHEN (CAST(DATEDIFF(Day, #searchDate, #EndDate) AS FLOAT) AS DECIMAL(16, 2)) = 0
THEN NULL -- Ideally it should return NULL but you can change it as per your requirement
ELSE CAST(CAST(Counter AS FLOAT) / CAST(DATEDIFF(Day, #searchDate, #EndDate) AS FLOAT) AS DECIMAL(16, 2))
END
The best way is NULLIF() . . . but you can't turn the value back into a 0:
select CAST(CAST(countAta AS float) /
NULLIF(DATEDIFF(day, #searchDate, #EndDate), 0
) as decimal(16, 2)
)
This returns NULL if the denominator is 0. Note that you don't have to cast to a float twice.
You could use NULLIF to avoid devided by zero error.
It returns NULL when denominator equals 0
CAST(countAta AS decimal(16,2)) /ISNULL(NULLIF(DATEDIFF(day,#searchDate,#EndDate),0), 1)
Or use CASE WHEN
CAST(countAta AS decimal(16,2)) /
CASE WHEN DATEDIFF(day,#searchDate,#EndDate) = 0 THEN 1
ELSE DATEDIFF(day,#searchDate,#EndDate)
END

Different results in SQL vs. VBA using POWER function and VBA equivalent

I'm hoping someone who is actually good at math can help me out with this. I get a different result in SQL than I do in VBA. In SQL, I have this function that calculates a payment. Variables for both VBA and SQL are:
Principal = 239762.05
Rate = 0.03 (aka 3%) ETA: in both cases, 0.03 is divided by 12, so really this is .0025
Period = 268
#principal / (power(1+#rate,#period)-1) * (#rate*power(1+#rate,#period))
In SQL this gives a value of 1228.76 (rounded)
In VBA, I do not have the POWER function. So I copied this public function from the internet:
Public Function Power(ByVal number As Double, ByVal exponent As Double) As Double
Power = number ^ exponent
End Function
And I am calling it in a sub here like so:
NewPI = PrinBal / (Power(1 + IntCalc, Term) - 1) * (IntCalc * Power(1 + IntCalc, Term))
but here, the answer I get is 1228.63 (rounded). Only 13 cents off!
I have tried lots of adjustments and either ended up with this same figure, or a much worse result. I am thinking it's some sort of Order of Operations mistake, but I'm not sure.
EDIT
I am adding this to possibly get to the bottom of the problem, which might be the data types in the SQL version. This is the full function
create function [dbo].[PMT] (#rate numeric(15,9), #periods smallint, #principal numeric(20,2) )
returns numeric(16,2)
as
begin
declare #pmt numeric (38,9)
select #pmt = #principal / (power(1+#rate,#periods)-1) * (#rate*power(1+#rate,#periods))
return #pmt
end
Short answer: Data types in SQL matter.
Worse, you can experience some implicit data conversion. Check this out...
DECLARE #RealPrincipal real
SET #RealPrincipal = 239762.05
DECLARE #RealRate real
SET #RealRate = 0.0025 --0.03 --(aka 3%) ETA: in both cases, 0.03 is divided by 12, so really this is .0025
DECLARE #Period int
SET #Period = 268
SELECT #RealPrincipal / (power(1.0+#RealRate,#Period)-1.0) * (#RealRate*power(1.0+#RealRate,#Period))
Result = 1228.61333410069
Compare that to your formula from your OP comment with all literals and no variables...
SELECT 239762.05 / (power(1+0.0025,268)-1) * (0.0025*power(1+0.0025,268)) as 'Value!'
Result = 1228.761629
Now, use the same exact structure as the first code block, but replace the real type variables with money type...
DECLARE #moneyPrincipal money
SET #moneyPrincipal = 239762.05
DECLARE #moneyRate money
SET #moneyRate = 0.0025 --(aka 3%) ETA: in both cases, 0.03 is divided by 12, so moneyly this is .0025
DECLARE #Period int
SET #Period = 268
SELECT #moneyPrincipal / (power(1+#moneyRate,#Period)-1) * (#moneyRate*power(1+#moneyRate,#Period))
Result = 1233.2921
Now, using the money data types, watch what happens when you replace the literal 1 values in the formula with 1.0 ...
SELECT #moneyPrincipal / (power(1.0+#moneyRate,#Period)-1.0) * (#moneyRate*power(1.0+#moneyRate,#Period))
Result = 1228.761629
This is a simply explanation. VBA is simply using a higher precision then SQL. Not saying this is best practice and i am sure someone else it going to SLAP / downvote me but if you change it too something like the below you will see it forces SQL to use more decimal places and you get the same answer.
select
#principal/(POWER((#rate+1)*1.000000000,#period*1.00000000000000000)-1)(#ratePOWER((#rate+1)*1.0000000000000000000,#period*1.00000000000000000))
Again there are better ways to do this, this is just the quick and dirty.
I think you should simplify your calculation:
In VBA:
function payment(principal as double, rate as double, term as integer) as double
' Inputs:
' principal: Ammount of the loan
' rate: Effective interest rate per period
' term: Number of periods / payments
dim v as double, a as double
v = 1 / (1 + rate)
a = (1 - (v ^ term) / rate)
payment = principal / a
end function
or, if you want it squeezed into a single line:
function payment(principal as double, rate as double, term as integer) as double
' Inputs:
' principal: Ammount of the loan
' rate: Effective interest rate per period
' term: Number of periods / payments
payment = principal * rate / (1 - ((1 + rate) ^ (-term)))
end function
and, in SQL:
#principal * #rate / (1 - power(1 + #rate, -#term))
-- #rate is the effective rate per period (in your example: 0.0025)
Minimize the number of arithmetic operations.
If you're having problems with data type (as LDMJoe mentions in his answer), you should try casting each variable to an appropriate data type. In Access you can do something like this (assuming you're writing the expression in a query):
CDbl(principal) * CDbl(rate) / (1 - power(1 + CDbl(rate), -CInt(term))
I'm also assuming that principal, rate and term are columns in a table.