conversion from nvarchar to numeric fails - sql

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.

Related

Scalar-valued function returning NULL

I have the below function, and for the life of me, I cannot get it to return a value, I get NULL every time.
I am calling it via select [dbo].[getFiatProfit](600.26,'GBP', 1000.99,'BTC') as op
What am I missing?
/****** Object: UserDefinedFunction [dbo].[getFiatProfit] Script Date: 06/07/2022 11:42:26 ******/
ALTER FUNCTION [dbo].[getFiatProfit] (
#fiatInvested float,
#fiatInvestedCurrency nvarchar,
#quantity float,
#currency nvarchar
)
RETURNS float
AS
BEGIN
declare #tmp float
declare #result float
declare #usdtgbp float
IF (#fiatInvestedCurrency = 'USD')
BEGIN
select #tmp = [dbo].[usdtPairs].[Value] from [dbo].[usdtPairs] where usdtPairs.ID = #currency;
select #usdtgbp = [dbo].[usdtPairs].[Value] from [dbo].[usdtPairs] where usdtPairs.ID = 'GBP';
set #result = (((#quantity * #tmp) - #fiatInvested) / #usdtgbp);
-- set #result = #quantity * #tmp;
END
ELSE
BEGIN
select #tmp = [dbo].[usdtPairs].[Value] from [dbo].[usdtPairs] where usdtPairs.ID = #currency;
set #result = ((#quantity * #tmp) - #fiatInvested);
-- set #result = #quantity * #tmp;
END
return (#result)
END
Your issue looks it's because your parameters are declared without a length. nvarchar defaults to a length of 1 in a lot of circumstances, so it's simply the wrong value being received. A much better data type would be char(3) which is fixed length, given that all currencies have exact three-letter names.
You should also convert this function into a Table Valued Function, which is likely to perform far better.
CREATE OR ALTER FUNCTION dbo.getFiatProfit (
#fiatInvested float,
#fiatInvestedCurrency char(3),
#quantity float,
#currency char(3)
)
RETURNS TABLE
AS RETURN
SELECT
result = ((#quantity * u.Value) - #fiatInvested)
/ (CASE WHEN #fiatInvestedCurrency = 'USD'
THEN 1
ELSE
(SELECT u2.Value FROM dbo.usdtPairs u2 WHERE u2.ID = 'GBP')
END)
FROM dbo.usdtPairs u
WHERE u.ID = #currency;
You use it like this
SELECT t.*, fp.*
FROM YourTable t
CROSS APPLY dbo.getFiatProfit(t.fiatInvested, t.fiatInvestedCurrency, t.Qty, 'GBP') fp;

Return two decimal points in create function

I have here an sql create function that will return float datatype.
I would like to know if how am I going to show the results to two decimal points.
ALTER FUNCTION [dbo].[udf_get_total]
(
-- Add the parameters for the function here
#code as int
)
RETURNS FLOAT
AS
BEGIN
-- Declare the return variable here
DECLARE #quantity as FLOAT
DECLARE #price as FLOAT
-- Add the T-SQL statements to compute the return value here
SET #quantity = (SELECT quantity FROM Requested_Item where Code_id = #code)
SET #price = (SELECT price FROM Requested_Item where Code_id = #code)
-- Return the result of the function
RETURN #quantity * #price
END
The sample results:
1632.1740985705144
6323.8092596543638
Use CAST
select cast(float_column as decimal(10,2))
from your_table
decimal(10,2) will display 10 digits before the point and 2 after it.
First of all. I'd rewrite your function. You're querying your table twice. This can be done by running a single SELECT statement. See this code:
ALTER FUNCTION [dbo].[udf_get_total]
(
#code AS INT
)
RETURNS FLOAT
AS
BEGIN
-- Declare the return variable here
DECLARE #quantity AS FLOAT
, #price AS FLOAT;
SELECT #quantity = quantity, #price = price
FROM Requested_Item
WHERE Code_id = #code;
-- Return the result of the function
RETURN #quantity * #price;
END
Now how to format your numbers properly? I used this method with CEILING and a bit of maths:
DECLARE #first FLOAT = 1632.1740985705144
, #second FLOAT = 6323.8092596543638;
SELECT FLOOR(#first * 100) / 100
, FLOOR(#second * 100) / 100;
It brings requested result:
╔═════════╦════════╗
║ 1632.17 ║ 6323.8 ║
╚═════════╩════════╝
Try this:
RETURN TRUNCATE(#quantity * #price, 2)
The 2 at the end means there will be 2 decimal points. You can really use the TRUNCATE function anywhere - the only downside is that it doesn't really round the numbers.
I only changed the return statement of my function to
RETURN CAST ((#total / #cur_amount) as decimal(10,2))
and it shows the 2 decimal points.

An invalid floating point operation occurred when search long and latitude

I use this procedure in SQL to find the near locations on Bing map by Latitude and Longitude.
The procedure returns
An invalid floating point operation occurred
when I search by this #latitude = 7025045 , #longitude = 702342
Here is my procedure:
ALTER PROCEDURE [dbo].[UppdragNearByUppdrag3]
#latitude int,
#longitude int
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
SELECT ARUppdrag.cUppdrNr AS UppdrNr, a.iLarmNorthing AS LarmKoordinatNorthing, a.iLarmEasting AS LarmKoordinatEasting
FROM Trakt AS a INNER JOIN
ARUppdrag ON a.iTraktID = ARUppdrag.iTraktID
WHERE a.iLarmNorthing <> 0 and a.iLarmEasting <> 0 And (ACOS(SIN(a.iLarmNorthing * 0.0175) * SIN(#latitude * 0.0175) + COS(a.iLarmNorthing * 0.0175) * COS(#latitude * 0.0175) *
COS(#longitude * 0.0175 - a.iLarmEasting * 0.0175)) * 3959 <= 100)
END
Cast the #longitude and #latitude to float or decimal with a large precision. Because they are INT, when they appear as the first variable in a mathematical statement, there is an implicit type cast to INT, and then there is an invalid float point operation.

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

Haversine formula using SQL server to find closest venue - vb.net

I am grabbing a postcode from a form. I can then convert this postcode to lng,lat coordinates as I have these stored in a table.
SELECT lng, lat from postcodeLngLat WHERE postcode = 'CV1'
I have another table which stores the lng,lat of a selection of venues.
SELECT v.lat, v.lng, v.name, p.lat, p.lng, p.postcode, 'HAVERSINE' AS distance FROM venuepostcodes v, postcodeLngLat p WHERE p.outcode = 'CB6' ORDER BY distance
What I am trying to do is create a datagrid which shows the distance of each venue from the postcode (CV1 in this case). I know that the Haversine formula should do what I am trying to achieve but I'm lost as to where I should start incorporating it into my query. I think the formula needs to go where I've put 'HAVERSINE' in the query above.
Any ideas?
EDIT
SELECT o.outcode AS lead_postcode, v.venue_name, 6371.0E * ( 2.0E *asin(case when 1.0E < (sqrt(square(sin(((RADIANS(CAST(o.lat AS FLOAT)))-(RADIANS(CAST(v.lat AS FLOAT))))/2.0E)) + (cos(RADIANS(CAST(v.lat AS FLOAT))) * cos(RADIANS(CAST(o.lat AS FLOAT))) * square(sin(((RADIANS(CAST(o.lng AS FLOAT)))-(RADIANS(CAST(v.lng AS FLOAT))))/2.0E))))) then 1.0E else (sqrt(square(sin(((RADIANS(CAST(o.lat AS FLOAT)))-(RADIANS(CAST(v.lat AS FLOAT))))/2.0E)) + (cos(RADIANS(CAST(v.lat AS FLOAT))) * cos(RADIANS(CAST(o.lat AS FLOAT))) * square(sin(((RADIANS(CAST(o.lng AS FLOAT)))-(RADIANS(CAST(v.lng AS FLOAT))))/2.0E))))) end )) AS distance FROM venuepostcodes v, outcodepostcodes o WHERE o.outcode = 'CB6' ORDER BY distance
I think you'd do best putting it in a UDF and using that in your query:
SELECT v.lat, v.lng, v.name, p.lat, p.lng, p.postcode, udf_Haversine(v.lat, v.lng, p.lat, p.lng) AS distance FROM venuepostcodes v, postcodeLngLat p WHERE p.outcode = 'CB6' ORDER BY distance
create function dbo.udf_Haversine(#lat1 float, #long1 float, #lat2 float, #long2 float) returns float begin
declare #dlon float, #dlat float, #rlat1 float, #rlat2 float, #rlong1 float, #rlong2 float, #a float, #c float, #R float, #d float, #DtoR float
select #DtoR = 0.017453293
select #R = 3937 --3976
select
#rlat1 = #lat1 * #DtoR,
#rlong1 = #long1 * #DtoR,
#rlat2 = #lat2 * #DtoR,
#rlong2 = #long2 * #DtoR
select
#dlon = #rlong1 - #rlong2,
#dlat = #rlat1 - #rlat2
select #a = power(sin(#dlat/2), 2) + cos(#rlat1) * cos(#rlat2) * power(sin(#dlon/2), 2)
select #c = 2 * atn2(sqrt(#a), sqrt(1-#a))
select #d = #R * #c
return #d
end
Alternatively uou could also use SQL Server 2008 geography datatypes. If you currently store the longitude/latitide as varchar() in the DB, you will have to store them as geograpghy datatype and then use a function like STIntersects() to get the distance.