Calculation using SQL server - sql

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)

Related

Difference between 2 numbers and return a %

I'm Looking to see if I can return a % from the following, but it need finishing.
SELECT COUNT(*) FROM VEHICLES_FW
WHERE ARCHIVE_STATUS_FW = 'N'
AND LOCATION_CODE_FW IN ('L0078')
This brings me back the amount of vehicle on this location. I know that the location has a limit of 180.
How do I write in so it works out that the % is 31%?
Ok, how i don't know what SQL variant you use, I write my response how I'll write on SQL Server.
If you want % respect of limit (180)
DECLARE #PERCENTAGE DECIMAL --Or INT if you prefer it
SET #PERCENTAGE = (SELECT COUNT(*) FROM VEHICLES_FW
WHERE ARCHIVE_STATUS_FW = 'N'
AND LOCATION_CODE_FW IN ('L0078')) * (100 / 180)
RETURN PERCENTAGE;
If you want % respect all cars
DECLARE #PERCENTAGE DECIMAL --Or INT if you prefer it
DECLARE #TOTAL DECIMAL --Or INT if you prefer it
SET #TOTAL = (SELECT COUNT(*) FROM VEHICLES_FW)
SET #PERCENTAGE = (SELECT COUNT(*) FROM VEHICLES_FW
WHERE ARCHIVE_STATUS_FW = 'N'
AND LOCATION_CODE_FW IN ('L0078')) * (100 / 180)
RETURN PERCENTAGE;

SQL Server - Calculate Initial Bearing from Latitude & Longitude using GEOGRAPHY

Recently, from the help of Stackoverflow members, I got the following solution to calculate distance between two latitude and longitude points:
GEOGRAPHY::Point(DepartureAirportLatitude, DepartureAirportLongitude, 4326)
.STDistance(GEOGRAPHY::Point(ArrivalAirportLatitude, ArrivalAirportLongitude, 4326)) AS [Default],
GEOGRAPHY::Point(DepartureAirportLatitude, DepartureAirportLongitude, 4326)
.STDistance(GEOGRAPHY::Point(ArrivalAirportLatitude, ArrivalAirportLongitude, 4326)) / 1609.344 AS [Mi],
GEOGRAPHY::Point(DepartureAirportLatitude, DepartureAirportLongitude, 4326)
.STDistance(GEOGRAPHY::Point(ArrivalAirportLatitude, ArrivalAirportLongitude, 4326)) / 1000 AS [Km]
Is there a way, using the GEOGRAPHY feature, to calculate the initial bearing between the same data points, displaying it as a heading?
Thanks
Matthew
Thanks for your reply and the information.
After a few hours of playing around and extensive amounts of Google searching, I am using the below solution which is giving me the correct results:
DECLARE #Pi AS FLOAT
DECLARE #D2R AS FLOAT
SET #Pi = '3.14159265358979'
SET #D2R = #Pi / 180.0;
PICalculation AS
(
SELECT FlightNo, DepartureAirportIATA, ArrivalAirportIATA,
#D2R * DepartureAirportLatitude AS [DepartureAirportLatitude], #D2R * DepartureAirportLongitude AS [DepartureAirportLongitude],
#D2R * ArrivalAirportLatitude AS [ArrivalAirportLatitude], #D2R * ArrivalAirportLongitude AS [ArrivalAirportLongitude]
FROM RawData
),
RadiansCalculation AS
(
SELECT FlightNo, DepartureAirportIATA, ArrivalAirportIATA,
Radians(ArrivalAirportLatitude - DepartureAirportLatitude) AS [DLat],
Radians(ArrivalAirportLongitude - DepartureAirportLongitude) AS [DLon],
Radians(DepartureAirportLatitude) AS [RLat1],
Radians(ArrivalAirportLatitude) AS [RLat2]
FROM PICalculation
),
XYCalculation AS
(
SELECT FlightNo, DepartureAirportIATA, ArrivalAirportIATA,
SIN(DLon)*COS(RLat2) AS [Y],
COS(RLat1)*SIN(RLat2)-SIN(RLat1)*COS(RLat2)*COS(DLon) AS [X]
FROM RadiansCalculation
),
HeadingCalculation AS
(
SELECT FlightNo, DepartureAirportIATA, ArrivalAirportIATA,
CASE WHEN X = 0 AND Y = 0 THEN 0
ELSE CAST((DEGREES(ATN2(Y,X)) + 360) AS DECIMAL(5,1)) % 360
END AS [InitialBearing]
FROM XYCalculation
)
SELECT *
FROM DataJoin
Hopefully this solution will be useful to others who stumble across this post as well :)
Matthew
Here's a scalar function and test points that exercise it. NB: I found the source here
CREATE FUNCTION dbo.Bearing (
#point1 geography,
#point2 geography )
RETURNS float
AS
BEGIN
DECLARE #Bearing decimal(18,15)
DECLARE #Lat1 float = Radians(#point1.Lat)
DECLARE #Lat2 float = Radians(#point2.Lat)
DECLARE #dLon float = Radians(#point2.Long - #point1.Long)
IF (#point1.STEquals(#point2) = 1)
SET #Bearing = NULL
ELSE
SET #Bearing = ATN2(
sin(#dLon)*cos(#Lat2),
(cos(#Lat1)*sin(#Lat2)) - (sin(#Lat1)*cos(#Lat2)*cos(#dLon))
)
SET #Bearing = (Degrees(#Bearing) + 360) % 360
RETURN #Bearing
END
GO
DECLARE #g GEOGRAPHY = GEOGRAPHY::Point(43, 43, 4326);
DECLARE #g1 GEOGRAPHY = GEOGRAPHY::Point(42, 43, 4326);
DECLARE #g2 GEOGRAPHY = GEOGRAPHY::Point(44, 43, 4326);
DECLARE #g3 GEOGRAPHY = GEOGRAPHY::Point(43, 42, 4326);
DECLARE #g4 GEOGRAPHY = GEOGRAPHY::Point(43, 44, 4326);
SELECT dbo.[Bearing](#g, #g1),
[dbo].[Bearing](#g, #g2),
[dbo].[Bearing](#g, #g3),
[dbo].[Bearing](#g, #g4);
If doing this in T-SQL ends up being too slow, there are a couple of CLR implementations at that link as well.

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

Cumulative Summation in SQL Server

I'm writing a query, part of Stored Procedure in SQL Server. I need to find cumulative summation in SQL Server.
A variable will hold a integer value say 100. Let's say
Declare #Variable int = 100
Now the #NewVariable will have below formula:
#NewVariable = #Variable * (1 - 0.005)
Hence #NewVariable = 99.5
Now, the #NewestVariable will have below formula;
#NewestVariable = #NewVariable * (1 - 0.005)
Hence the #NewestVariable will have value of 99.00
Likewise this calculation will occur 24 times and all the results will be sum at the end.
Hence final result will be: 100 + 99.5 +99.00 + .... ...
I tried to achieve the desired result using #Count Variable (DECLARE #COUNT INT = 24) and using a While loop, but I'm not sure whether I'm correct or not?
Request your help!
Thanks!
You can do it using a CTE as below:
declare #variable int = 100
;with cte as
(
select convert(numeric(8,2), #variable) as var, 1 as recCount
union all
select convert(numeric(8,2), #variable * (1 - recCount*0.005)) as var, recCount+1 as recCount
from cte
where recCount < 24
)
select sum(var) as total from cte
Working Fiddle Demo
Edit: Adjusted to resolve rounding error as per #peter.petrov 's comment
If you need to get the values of each row before counting, please use this fiddle
Try this code.
declare #Variable decimal(20,10);
set #Variable = 100;
declare #Sum decimal(20,10);
set #Sum = 0;
declare #cnt int;
set #cnt = 1;
while (#cnt <= 24)
begin
set #Sum = #Sum + #Variable;
set #Variable = #Variable * (1.0 - 0.005);
set #cnt = #cnt + 1;
end;
select #Sum;
A simple answer would be like this
DECLARE #Variable INT = 100
SELECT #Variable
DECLARE #counter INT = 1
DECLARE #SumVariable NUMERIC(20,2) = #Variable
DECLARE #NewVariable NUMERIC(20,2) = #Variable
WHILE(#counter<24)
BEGIN
SET #NewVariable = #NewVariable * 0.995
SET #SumVariable = #SumVariable + #NewVariable
SET #counter = #counter+1
END
SELECT #SumVariable
You could also use a "quirky update" to avoid while-loops. If you're not interesed in intermediate resuls, just modify the last code line to select only the max(total).
DECLARE #total DECIMAL(10,3) = 0.000
;WITH "data" AS
(
SELECT CAST( 100 AS DECIMAL(10,3)) AS id
UNION ALL
SELECT CAST( id * ( 1 - 0.005 ) AS DECIMAL(10,3)) FROM "data" WHERE id > 100 * (1 - 21 * 0.005)
)
SELECT
id, total = CAST( 0.000 AS DECIMAL(10,3))
INTO #temp
FROM
"data"
OPTION ( MAXRECURSION 23 );
UPDATE t SET #total = total = #total + id FROM #temp t
SELECT * FROM #temp
See SQL-Fiddle for testing.