NPER excel function in SQL - sql

Has anybody figured out how to use NPER excel function to SQL? Use case is that I am trying to find the remaining terms of an acct in SQL.
Fields:
Current_principalbalance - PV
Current_interestrate/100/12 - RATE
Current_paymentamount- PMT
No types in data
no FV in data
I tried:
Use NLS
go
declare #fv float
declare #rate float
declare #Pmt float
declare #k float
declare #pv float
set #fv=0
set #rate=(select (current_interest_rate/100/12) from loanacct)
set #pmt= (select amortized_payment_amount from loanacct_payment)
set #pv = (select current_principal_balance from loanacct)
set #k=1
select Log10((-#Fv * (#Rate / #k) + #Pmt)
/ (#Pmt + (#Rate / #k) * #Pv))
/ Log10(1 + #Rate) as nper
from loanacct a, loanacct_detail b, loanacct_setup c, loan_class d, loan_group e, loanacct_payment f
where a.acctrefno = b.acctrefno
and b.acctrefno = c.acctrefno
and a.loan_class2_no = d.codenum
and e.loan_group_no = a.loan_group_no
and f.acctrefno = a.acctrefno
and e.loan_group_no = 55
and a.loan_number IN (66515,67214,65980)
but now i get the error: Msg 512, Level 16, State 1, Line 9
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.

Since NPER is a forumla it would be possible to implement it in SQL since the operators for a formula would almost always be supported in databases
When using "Log" in your query, the natural logarithm is considered, and nper uses the Log to base 10. Therefore the formula should be altered as
select Log10((-#Fv * (#Rate / #k) + #Pmt)
/ (#Pmt + (#Rate / #k) * #Pv))
/ Log10(1 + #Rate) as nper
Here is a test case which compares the value from excel nper function and one from the sql server database, that matches using your example..
--I have edited the datatypes to be float
declare #fv float
declare #rate float
declare #Pmt float
declare #k float
declare #pv float
set #fv=0
set #rate=15.99/100/12
set #pmt=-167.65
set #pv =1491.42
set #k=1
--In case the interests obtained at start of period then set #k as follows
--set #k = 1 + #rate
select Log10((-#Fv * (#Rate / #k) + #Pmt)
/ (#Pmt + (#Rate / #k) * #Pv))
/ Log10(1 + #Rate) as nper
+------------------+
| nper |
+------------------+
| 9.53201056406188 |
+------------------+
Excel
=NPER(15.99/100/12, -167.65,1491.42,0)
Here is a dbfiddle link
https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=2f470cee443e10647f83d6e640129d51

For this use case this was my solution and it works perfect to NPER function in excel:
declare #fv float
declare #k float
set #fv=0
set #k=1
select CEILING(Log10((-#Fv * ((current_interest_rate/100/12) / #k) + -amortized_payment_amount)
/ (-amortized_payment_amount + ((current_interest_rate/100/12) / #k) * current_principal_balance))
/ Log10(1 + (current_interest_rate/100/12))) as nper

Related

Calculation using SQL server

Formula used
This is the formula that I used to calculate
Expressed as a single equation:
eGFR = 142 x min(Scr/κ, 1)α x max(Scr/κ, 1)-1.200 x 0.9938Age x 1.012 [if female]
where:
Scr = serum creatinine in mg/dL
κ = 0.7
α = -0.329
min(Scr/κ, 1) is the minimum of Scr/κ or 1.0
max(Scr/κ, 1) is the maximum of Scr/κ or 1.0
Age (years)
Code that I tried
select
ROUND(141 * power(min(cast(40 as float) / 0.7 ) ,-0.329) *
power(max( cast(40 as float) / 0.7 * 1) ,- 1.209) * 0.993 *
cast(42 as float) * 1.018 ,2) as kidney
Correct answer should be 123.
Any clue what I am missing in the query?
Don't use MIN and MAX, those are aggregate (GROUP BY) functions. It would be good if SQL Server had GREATEST and LEAST functions, but it doesn't yet.
IIF(a < b, a, b) is LEAST(a,b).
IIF(a > b, a, b) is GREATEST(a,b).
Don't sweat the CASTs.
Make no assumptions about operator precedence ( x before +, etc). Use parentheses.
Here's a rewrite of what I believe your formula should be. But I'm not getting the right answer yet either.
DECLARE #Scr AS INT = 40;
DECLARE #k AS FLOAT = 0.7;
DECLARE #a AS FLOAT = -0.329;
DECLARE #age AS INT = 42;
DECLARE #gender AS VARCHAR(MAX) = 'female';
DECLARE #factor AS FLOAT = CASE WHEN #gender = 'male' THEN 1.0 ELSE 1.012 END;
SELECT 142
+ (IIF(1 < #Scr/#k, 1, #Scr/#k) * #a)
* (IIF(1 > #Scr/#k, 1, #Scr/#k))
- (1.2 * 0.993 * #age * #factor);
I obviously misunderstood your formula, but this should get you started. Here's a fiddle.
According to this site your equation is kinda wrong. Please be sure to add ^ to display the "to the power of".
DECLARE #Scr AS FLOAT = 40.0;
DECLARE #gender AS VARCHAR(10) = 'female';
DECLARE #age AS SMALLINT = 42;
DECLARE #k AS FLOAT = CASE WHEN #gender = 'male' THEN 0.9 ELSE 0.7 END;
DECLARE #a AS FLOAT = CASE WHEN #gender = 'male' THEN -0.302 ELSE -0.241 END;
DECLARE #factor AS FLOAT = CASE WHEN #gender = 'male' THEN 1.000 ELSE 1.012 END;
SELECT 142 * POWER(IIF(1 < (#Scr/#k), 1, #Scr/#k), #a)
* POWER(IIF(1 > (#Scr/#k), 1, #Scr/#k), -1.200)
* POWER(0.9938, #age)
* #factor;
Also this result is correct since it is calculated in mg/dl and your expected value is in umol/l
Here is another website (it may be german, but it should do the trick)

conversion from nvarchar to numeric fails

I am trying to execute this query but the following error is occurring:
Error converting data type nvarchar to numeric
this is my query :
Select Top 20 *,dbo.GetDistance(35.5,33.8, Longitude, Latitude) as Distance
From ViewBranchCoordinates
order by Distance desc
if i remove this line order by Distance desc the query run normally with no error
this is the function GetDistance
ALTER FUNCTION [dbo].[GetDistance]
(
-- Add the parameters for the function here
#Long decimal(30,24), #Lat decimal(30,24), #Long2 decimal(30,24), #Lat2 decimal(30,24)
)
--decimal(8,6), #Long)
RETURNS decimal(38,28)
AS
BEGIN
-- Declare the return variable here
DECLARE #Distance decimal(38,28)
DECLARE #valueOne decimal(30,24)
DECLARE #valueTwo decimal(30,24)
DECLARE #dLat decimal(30,24)
DECLARE #dLng decimal(30,24)
DECLARE #SectionOne decimal(30,24)
DECLARE #SectionTwo decimal(30,24)
Select #dLat = RADIANS(#Lat - #Lat2)
Select #dLng = RADIANS(#Long - #Long2)
Select #SectionOne = square(sin((#dLat)/2))
Select #SectionTwo = cos(RADIANS(#Lat)) * cos(RADIANS(#Lat2)) * square(sin(#dLng / 2))
Select #valueOne =CONVERT(decimal(30,24),#SectionOne + #SectionTwo)
Select #valueTwo = 2 * ATN2(SQRT(#valueOne), SQRT(1 - #valueOne))
Select #Distance = 6371000 * #valueTwo
RETURN #Distance
END
Any help please
I presume this will fail too?
Select Top 20 *
,dbo.GetDistance(35.5,33.8, cast (Longitude as decimal (30,24)), cast(Latitude as (30,24)) as Distance
From ViewBranchCoordinates
Your function expects data of a certain type. If your lat/long columns are nvarchar then non numeric data can be in those columns.
Search for problem data, e.g.
Select *
From ViewBranchCoordinates
Where try_cast (longitude as numeric) IS NULL
Then you need to fix the data.

How do I get an int

Seems like a simple question... but I am stumped.
declare #Total_User int
set #Total_User = 8
declare #Total int
set #Total = 12
declare #Number int
set #Number = (#Total_User / #Total) * 100
select #Number as 'Standard'
I am expecting 66, but my select comes out zero ??
What am I doing wrong?
The result of (#Total_User / #Total) is zero, as it is doing integer division.
You can multiply by 100 first, which gives the result that you expected:
set #Number = 100 * #Total_User / #Total
To get a rounded value rather than truncated, you would use floating point values and the round function:
set #Number = round(100.0 * #Total_User / #Total, 0)
This will give the result 67 rather than 66, as that is closer to the actual result 66.6666666666
Try:
set #Number = (#Total_User*100 / #Total)
Your division #Total_User / #Total is using integer arithmetic i.e. any remainder will be discarded, so that part of the expression will be 0.
To fix, write (1.0 * #Total_User / #Total) * 100. This promotes the operation to floating point.
You are doing integer arithmetic, that is why you see the 0, make at least one of the operand as float and you will see the correct result like:
declare #Total float
Or you can cast one operand as float like:
et #Number = (CAST(#Total_User as float) / #Total) * 100
Your current code is doing:
8 / 12
Which would result in 0.666666666667, but since both of your operands are of type int the calculation is performed using int type, thus result in 0 and not 0.66666666667.
You get 0 because you are doing integer division of #Total_User and #Total.
You have two options to get the correct result:
First multiply Ttotal_User by 100 and then divide by #Total:
set #Number = (#Total_User * 100) / #Total
Cast #Total_User and #Total to floating point before making the division:
set #Number = (cast(#Total_User as float) / cast(#Total as float)) * 100
declare #Total_User float,
#Total float,
#Number float
SET #Total_User = 8
SET #Total = 12
SET #Number = #Total_User / #Total * 100
select CAST(#Number AS INT) AS 'Standard'
This will give you 66

Float data type will not work with bankers rounding -- SQL Server 2008

To provide some background, I am currently working on a project of transitioning an Access database and its code to SQL.
In the process I changed Access data types of Double to Float in SQL Server; I did this because these data types are closely related and because my database performs a lot of division and multiplication (something I heard floats were best for).
Another issue of converting the database arose in the fact that Access uses bankers rounding whereas SQL does not; I went out and found two UD bankers rounding functions, both are not yielding consistent bankers rounding results as they should.
Is this inconsistency something I should expect when trying to run these bankers rounding functions (which include subtraction and addition) on float numbers?
The following are the two functions...
FUNCTION [dbo].[RB](#Val FLOAT, #Digits INT)
RETURNS FLOAT
AS
BEGIN
RETURN CASE WHEN ABS(#Val - ROUND(#Val, #Digits, 1)) * POWER(10, #Digits+1) = 5
THEN ROUND(#Val, #Digits, CASE WHEN CONVERT(INT, ROUND(ABS(#Val) *
POWER(10,#Digits), 0, 1)) % 2 = 1 THEN 0 ELSE 1 END)
ELSE ROUND(#Val, #Digits)
END
END
FUNCTION [dbo].[RoundBanker]
( #Amt NUMERIC(38,16)
, #RoundToDecimal TINYINT
)
RETURNS NUMERIC(38,16)
AS
BEGIN
DECLARE #RoundedAmt NUMERIC(38,16)
, #WholeAmt INT
, #Decimal TINYINT
, #Ten NUMERIC(38,16)
SET #Ten = 10.0
SET #WholeAmt = ROUND(#Amt,0, 1 )
SET #RoundedAmt = #Amt - #WholeAmt
SET #Decimal = 16
WHILE #Decimal > #RoundToDecimal
BEGIN
SET #Decimal = #Decimal - 1
IF 5 = ( ROUND(#RoundedAmt * POWER( #Ten, #Decimal + 1 ) ,0,1) -
(ROUND(#RoundedAmt * POWER( #Ten, #Decimal ) ,0,1) * 10) )
AND 0 = cast( ( ROUND(#RoundedAmt * POWER( #Ten, #Decimal ) ,0,1) -
(ROUND(#RoundedAmt * POWER( #Ten, #Decimal - 1 ) ,0,1) * 10) )
AS INTEGER ) % 2
SET #RoundedAmt = ROUND(#RoundedAmt,#Decimal, 1 )
ELSE
SET #RoundedAmt = ROUND(#RoundedAmt,#Decimal, 0 )
END
RETURN ( #RoundedAmt + #WholeAmt )
END
SQL Server ROUND() function follows IEEE Standard 754 and uses the "round up" algorithm when you use float type. Use decimal if you need more precision. dont use use float or real.
refer this link http://msdn.microsoft.com/en-us/library/ms187912.aspx

how to truncate a number in sybase ASE?

http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.infocenter.dc38151.1540/doc/html/san1278453173757.html
The functions TRUNCATE and TRUNCNUM are not supported in Adaptive Server Enterprise.
Does anyone know another way of doing this in ASE?
Thanks
I know these ways:
select Number = floor ( 455.443 )
select Number = cast ( 455.443 as int )
select Number = convert ( int, 455.443 )
select Number = 455.443 - ( 455.443 % 1 )
How about using the Floor function? It essentially does the same thing, and is supported in ASE.
This is an old question, but I did this a few days ago to mimic the "truncnum" function described in the link above.
create function custom_truncnum(#numberToTruncate float, #decimalPlaces int)
returns float
AS
declare #tenToTheXPower float;
declare #leftSideOfDecimal float;
declare #returnVal float;
set #tenToTheXPower = power(10, ABS(#decimalPlaces);
set #leftSideOfDecimal = FLOOR(#numberToTruncate);
if (#decimalPlaces <= 0)
set #returnVal = FLOOR(#numberToTruncate / #tenToTheXPower) * #tenToTheXPower;
else
set #returnVal = #leftSideOfDecimal + (FLOOR(#numberToTruncate - #leftSideOfDecimal) * #tenToTheXPower) / #tenToTheXPower);
return #returnVal;
GO
Now you should be able to do this in Sybase ASE:
SELECT dbo.custom_truncnum(345.567, 2)
345.56
SELECT dbo.custom_truncnum(345.562, 2)
345.56
SELECT dbo.custom_truncnum(345.567, -1)
340
SELECT dbo.custom_truncnum(345.567, -2)
300
SELECT dbo.custom_truncnum(345.567, 0) --This is the same as FLOOR(345.567)
345