我试图在下面的函数中添加两个参数,并将结果返回为DECIMAL(@ p1,@ p2),但是我遇到了语法错误-我该怎么做?
/*
---------------------------------------------------------------------------------
SELECT [dbo].fn_ConvertTextToDecimal_19_4('', 0) -- NULL
SELECT [dbo].fn_ConvertTextToDecimal_19_4('', 1) -- 0.0000
SELECT [dbo].fn_ConvertTextToDecimal_19_4('100', 1) -- 100.0000
SELECT [dbo].fn_ConvertTextToDecimal_19_4('1234567890123456.1234', 0) -- NULL
---------------------------------------------------------------------------------
*/
ALTER FUNCTION [dbo].[fn_ConvertTextToDecimal_19_4]
(
@Decimal_Number VARCHAR(50),
@Fail_As_Zero BIT
)
RETURNS DECIMAL(19, 4)
AS
BEGIN
RETURN
(
CASE WHEN
TRY_CAST(@Decimal_Number AS DECIMAL(19, 4)) IS NULL
THEN
CASE WHEN (@Fail_As_Zero = 1)
THEN 0
ELSE NULL
END
ELSE
TRY_CAST(@Decimal_Number AS DECIMAL(19, 4))
END
)
END
更新 -在我发现它需要与SQL Server 2008兼容之后,我添加了这个宝贝:
/*
---------------------------------------------------------------------------------
PURPOSE : Convert a string into decimal(19,4)
(this is a workaround for SQL server 2008 where TRY_CAST cannot be used)
based on https://stackoverflow.com/questions/11089125/varchar-to-decimal
otherwise it can be casted as follows:
ISNULL(TRY_CAST([column_name] AS DECIMAL(19, 4)), 0) AS [Test_1]
ISNULL(TRY_CAST([column_name] AS DECIMAL(19, 4)), NULL) AS [Test_2]
NOTE : for different precision, change the constants in the code (19, 4, 16)
USAGE :
SELECT [dbo].fn_ConvertTextToDecimal_19_4('', 0) -- NULL
SELECT [dbo].fn_ConvertTextToDecimal_19_4('', 1) -- 0.0000
SELECT [dbo].fn_ConvertTextToDecimal_19_4('100', 1) -- 100.0000
SELECT [dbo].fn_ConvertTextToDecimal_19_4('-123456789012345.1234', 0) -- -123456789012345.1234
---------------------------------------------------------------------------------
*/
CREATE FUNCTION [dbo].[fn_ConvertTextToDecimal_19_4]
(
@Decimal_Number VARCHAR(50),
@Fail_As_Zero BIT
)
RETURNS DECIMAL(19, 4)
AS
BEGIN
RETURN
(
CASE WHEN ISNUMERIC(@Decimal_Number) = 1
AND CHARINDEX('.', @Decimal_Number) = 0
AND LEN(REPLACE(REPLACE(@Decimal_Number, '-', ''), '+', '')) < 16
THEN CONVERT(DECIMAL(19, 4), @Decimal_Number)
WHEN ISNUMERIC(@Decimal_Number) = 1
AND (CHARINDEX('.', @Decimal_Number) !=0
AND CHARINDEX('.', REPLACE(REPLACE(@Decimal_Number, '-', ''), '+', '')) <= 16)
THEN CONVERT(DECIMAL(19, 4),
CASE WHEN LEN(@Decimal_Number) - LEN(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@Decimal_Number, '0', ''), '1', ''), '2', ''), '3', ''), '4', ''), '5', ''), '6', ''), '7', ''), '8', ''), '9', '')) <= 19
THEN @Decimal_Number
ELSE SUBSTRING(@Decimal_Number, 1, 19 + LEN(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@Decimal_Number, '0', ''), '1', ''), '2', ''), '3', ''), '4', ''), '5', ''), '6', ''), '7', ''), '8', ''), '9', '')))
END
)
ELSE
CASE WHEN (@Fail_As_Zero = 1)
THEN 0
ELSE NULL
END
END
)
END
GO
幻数是:(38,10,29)(19,6,14)(19,4,16)
答案 0 :(得分:2)
您不能在SQL Server中(以合理的方式)执行此操作。问题?您不能将精度和长度作为参数传递给decimal
。
“显而易见的”解决方案是使用动态SQL。 las,那是行不通的,因为函数无法调用动态SQL(虽然有一种方法,但是它涉及太多的开销,您不妨嘲笑这种解决方法)。
另一种解决方案将是一个非常有趣的case
表达式:
(case when @p = 1 and @s = 1 then try_cast(@input as decimal(1, 1))
. . .
大约只有38 * 38/2 = 722个条件(精度不能小于刻度)。
我不确定您为什么真正关心数字的精度和小数位数。为什么不只使用str()
或format()
并转换为具有所需表示形式的字符串呢?
编辑:
写完所有这些之后,我意识到该函数必须返回单个类型。您无法在返回值上参数化小数位数和精度,因此SQL Server根本不支持您要执行的操作。