Converting varchar to decimal removes digits - sql

I made a SQL Server function that converts varchar to a decimal but it's removing digits and then returning a whole number.
Create FUNCTION [dbo].[ToMoney]
(
#Amount nvarchar
)
RETURNS decimal(14,2)
AS
BEGIN
-- Declare the return variable here
DECLARE #finalAmount as decimal(14,2);
IF Isnumeric(isnull(#amount, 0)) = 1
SET #finalAmount = CAST(#amount as decimal(14,2))
ELSE
SET #finalAmount = 0
-- Return the result of the function
RETURN #finalAmount;
END
When I run the following query:
SELECT dbo.ToMoney('123.45') as result
The result is '1.00'
I want it to return 123.45 as a decimal. What am I doing wrong?

The problem is your function definition. The use of nvarchar() with no length generally defaults in a length of 1.
Try this:
Create FUNCTION [dbo].[ToMoney]
(
#Amount nvarchar(255)
)
RETURNS decimal(14,2)
As a note: when it defaults to the length of 1, it is taking the first character in the string. That is why you are getting a value of 1.00.

Related

Update Accumulated Value with CTE error because of decimal datatype (SQL)

I am trying to get the accumulated value of the column MontanteRecuperacao into montanterecuperacao_acumulada, by date and contract.
But the decimal datatype is becoming a problem and I don't know why, this works when the variables are of INT type.
This is the error message
Msg 4187, Level 16, State 1, Procedure spCalculaRecuperacao, Line 123
Data type decimal of receiving variable cannot store all values of the data type decimal of column 'montanterecuperacao_acumulada' without data loss.
Code:
DECLARE #MontanteRecuperacao_running DECIMAL,
#montanterecuperacao_acumulada_running DECIMAL,
#Contrato VARCHAR(10) = '' ;
WITH CTE AS
(
SELECT TOP 100 PERCENT
MontanteRecuperacao, montanterecuperacao_acumulada, ContratoId
FROM
MovimentoRecuperacao
ORDER BY
[ContratoId], [DtReferencia] DESC
)
UPDATE CTE
SET #montanterecuperacao_acumulada_running = montanterecuperacao_acumulada =
CASE
WHEN #Contrato <> ContratoId
THEN montanterecuperacao_acumulada
ELSE #montanterecuperacao_acumulada_running - #MontanteRecuperacao_running
END,
#MontanteRecuperacao_running = MontanteRecuperacao,
#Contrato = ContratoId
You've declared your DECIMAL parameters without specifying precision or scale:
#MontanteRecuperacao_running DECIMAL , #montanterecuperacao_acumulada_running DECIMAL
The default values are DECIMAL(18,0), which is essentially an integer. In order to get the behavior you desire, you'll need to assess your data for proper values to assign.

how to sum up value within one cell SQL

I have some binary values such as 00, 0000, 001000.11111000, 1111100000
I need to sum it up so it turns into 0, 0, 1, 5, 5 ( sum 0s and 1s up)
how can we do that in SQL please?
Thanks
Assumption:
The binary values are stored as string.
Each value is in its own cell in a table. Something like:
BinaryValues (Consider it a column name)
00
0000
001000
and so on.
You want to add up the individual digits to get the sum.
SQL Product you are usind supports functions, looping, string manipulation like substring, extracting string length etc.
As per my best knowledge these are primitives available in all SQL products.
Solution:
Write a function (call it by any name. Ex: AddBinaryDigits) which will take the binary value in string format as input.
Inside the function and do a string manipulation. Extract each digit and add it up. Return the sum as result.
Call the function:
If using binary values stored in a table:
SELECT AddBinaryDigits(BinaryValues) FROM <WhatEverTableName>
If using fixed value:
SELECT AddBinaryDigits('00')
SELECT AddBinaryDigits('0000')
SELECT AddBinaryDigits('001000')
and so on.
Edited to include the request to create function.
CREATE FUNCTION <funtionName>
(
#ParameterName AS VARCHAR(expected string length like 10/15/20 etc.)
)
RETURNS INT
BEGIN
SQL Code to sum
RETURN SummedUpValue
END
Use the below query. If needed convert it into function.
create function dbo.fnSumChars(#someInt VARCHAR(20))
RETURNS INT
AS
BEGIN
DECLARE #count INT = LEN(#someInt),
#counter INT = 1
DECLARE #Sum INT = 0
WHILE #counter <= #count
BEGIN
SELECT #sum += CAST(SUBSTRING(CAST(#someInt AS VARCHAR), #counter, 1) AS int)
SELECT #counter += 1
END
RETURN #sum --5
END
This is the function and you can call this function like below
SELECT dbo.fnSumChars('1111100000')
If these are already in string format, this is the easiest:
select len(replace('1111100000', '0', ''))
No need for a function either, because it can be inlined in the query. Functions, even the light ones, incure perf penalty.

How to handle a input into function which can be float or nvarchar (Function parameter is varchar)

I created a function [fnRemoveNonNumericCharacters] which takes phone numbers as input remove any characters other than numeric and returns only numeric part.
Example : if I pass (800)-123-1234 in to the function it removes the non numeric character and returns me 8001231234.
My inputs will be phone number which usually are float datatype. So I used
select [dbo].[fnRemoveNonNumericCharacters](Ltrim(str(Phone, 50, 0)))
to pass through and it used to work fine. But now I am getting nvarchar numbers like (800)-123-1234 as a source.
When I am using the above function it's erroring out:
'Error converting data type nvarchar to float'
Here is the function which I am using
Create Function [dbo].[fnRemoveNonNumericCharacters](#strText VARCHAR(1000))
RETURNS VARCHAR(1000)
AS
BEGIN
WHILE PATINDEX('%[^0-9]%', #strText) > 0
BEGIN
SET #strText = STUFF(#strText, PATINDEX('%[^0-9]%', #strText), 1, '')
END
IF (#strText Like '1%')
BEGIN
SET #StrText = Stuff(#StrText,1,1,'')
END
RETURN #strText
END
How can I handle both nvarchar and float numbers while passing in to the above function?
The STR function in sql server ex expecting a float datatype as the first argument and in this case your input is not float datatype , it is a nvarchar type. To solve this problem, i will suggest use the substring function with Cast function. Please find the sample sql below.
select ltrim(Substring(cast(phone_number as nvarchar(100)),0,50)) from test_phone
Here first you change the phone_number data type from float to navrachar and then using sub string you are collecting first 50 character and Ltrim for trimming purpose.
You can try this and hopefully your problem will be fixed.
Note: there are different ways to solve the same problem, the above problem may not be optimized one.
Regards - Sanjeeb

Sql function - disregarding the decimal place in returning value

Why is it that sql query will disregard the decimal place when using SUM function?
iv'e use CONVERT function but it doesn't return the right value.
example:
150.30 * 3 = 450.9
but on the result of my function it return
150.30 * 3 = 451 it round the decimal place.
how can i get the exact result of calculation...?
here's my sql function query
CREATE FUNCTION [dbo].[fnGetSubjectCost](#id INT)
RETURNS DECIMAL
AS
-- Returns the stock level for the product.
BEGIN
DECLARE #ret DECIMAL;
SELECT #ret = IIF([Name] = 'Tuition', CONVERT([DECIMAL](9,2),Cost) * CONVERT([DECIMAL](15,2),t1.SubjectUnit), CONVERT([DECIMAL](9,2),Cost))
FROM [HCCDB].[dbo].[SubjectOfferedFee] AS t0
INNER JOIN HCCDB.dbo.SubjectsOffered AS t1
ON t1.SubjectsOfferedID = t0.SubjectsOfferedID
WHERE t0.SubjectOfferedFeeID = #id
IF (#ret IS NULL)
SET #ret = 0;
RETURN CONVERT(DECIMAL(15,2), #ret);
END;
The query work but it did not return exact value. it disregard the decimal place.
purpose of this function is the add on column formula.
ALTER TABLE HCCDB.dbo.SubjectOfferedFee
ADD FinalCost AS CONVERT(DECIMAL(15,2), dbo.fnGetSubjectCost(CONVERT(INT, [SubjectOfferedFeeID])))
The problem is the declaration of #ret.
In SQL Server, the default scale for a decimal is 0 (see the documentation). So,
declare #ret decimal;
is equivalent to:
declare #ret decimal(18, 0);
Just be explicit about the precision and scale, something like:
declare #ret decimal(18, 2);

Round off to the smallest integer value

I'm using this query to round off the numbers and this round off the next value. Now I need to round off to the before value means if the value is 45.67 then the value should be 45. I tried these two queries and still I need to tweak the values.
Method1:
parsename('$' + convert(varchar,convert(money,round(sum(Column1 * Column2),0)),1),2)
Method2:
parsename('$' + convert(varchar,convert(money,floor(Column1 * Column2),0),1),2)
Really appreciate any suggestions.
The CEILING function returns the smallest integer greater than or equal to the specified numeric expression. The FLOOR function returns the largest integer less than or equal to the specified numeric expression. For example, in considering a numeric expression of 12.9273, CEILING returns 13 and FLOOR returns 12. The return value of both FLOOR and CEILING has the same data type as the input numeric expression.
SELECT CEILING(12.9273);
Here is the result set.
13
SELECT FLOOR(12.9273);
Here is the result set.
12
http://technet.microsoft.com/en-us/library/ms190927%28v=sql.105%29.aspx
To round down you can use FLOOR()
E.G.
DECLARE #number numeric(5,2)
SET #number = 45.67
SELECT FLOOR(#number)
You'd get the result 45
With your example, it looks like it's already working?
declare #number1 numeric(5,2)
declare #number2 numeric(5,2)
set #number1 = 1.23
set #number2 = 21.69
select parsename('$' + convert(varchar,convert(money,floor(#number1 * #number2),0),1),2)
select #number1 * #number2
Results
$26
26.6787