我有一些列的分数字符串(即6 11/32)或小数(1.5)。是否可以将CAST
或CONVERT
调用转换为一致的小数?
错误:
Msg 8114,Level 16,State 5,Line 1 将数据类型varchar转换为数字时出错。
我可以避免进行任何类型的解析吗?
谢谢!
P.S。我在SQL Server Management Studio 2012
工作。
答案 0 :(得分:3)
CREATE FUNCTION ufn_ConvertToNumber(@STR VARCHAR(50))
RETURNS decimal(18,10)
AS
BEGIN
DECLARE @L VARCHAR(50) = ''
DECLARE @A DECIMAL(18,10) = 0
SET @STR = LTRIM(RTRIM(@STR)); -- Remove extra spaces
IF ISNUMERIC(@STR) > 0 SET @A = CONVERT(DECIMAL(18,10), @STR) -- Check to see if already real number
IF CHARINDEX(' ',@STR,0) > 0
BEGIN
SET @L = SUBSTRING(@STR,1,CHARINDEX(' ',@STR,0) - 1 )
SET @STR = SUBSTRING(@STR,CHARINDEX(' ',@STR,0) + 1 ,50 )
SET @A = CONVERT(DECIMAL(18,10), @L)
END
IF CHARINDEX('/',@STR,0) > 0
BEGIN
SET @L = SUBSTRING(@STR,1,CHARINDEX('/',@STR,0) - 1 )
SET @STR = SUBSTRING(@STR,CHARINDEX('/',@STR,0) + 1 ,50 )
SET @A = @A + ( CONVERT(DECIMAL(18,10), @L) / CONVERT(DECIMAL(18,10), @STR) )
END
RETURN @A
END
GO
然后通过选择dbo.ufn_ConvertToNumber访问它(' 5 9/5')
答案 1 :(得分:1)
您需要解析。正如尼尔斯所说,这不是一个好主意;但是使用T-SQL标量函数可以很简单地完成它。
CREATE FUNCTION dbo.FracToDec ( @frac VARCHAR(100) )
RETURNS DECIMAL(14, 6)
AS
BEGIN
RETURN CASE
WHEN @frac LIKE '% %/%'
THEN CAST(LEFT(@frac, CHARINDEX(' ', @frac, 1) -1) AS DECIMAL(14,6)) +
( CAST(SUBSTRING(@frac, CHARINDEX(' ', @frac, 1) + 1, CHARINDEX('/', @frac, 1)-CHARINDEX(' ',@frac,1)-1) AS DECIMAL(14,6))
/ CAST(RIGHT(@frac, LEN(@frac) - CHARINDEX('/', @frac, 1)) AS DECIMAL(14,6)) )
WHEN @frac LIKE '%/%'
THEN CAST(LEFT(@frac, CHARINDEX('/', @frac, 1) - 1) AS DECIMAL(14,6)) / CAST(RIGHT(@frac, LEN(@frac) - CHARINDEX('/', @frac, 1)) AS DECIMAL(14,6))
ELSE
CAST(@frac AS DECIMAL(14,6))
END
END
GO
-- Test cases
SELECT dbo.FracToDec('22/7'), dbo.fracToDec('3.117'), dbo.fracToDec('7 3/4')
-- Output
-- 3.142857 3.117000 7.750000
请注意,如果传递的内容实际上与表格不匹配,则此操作将失败" mm / nn"," xx mm / nn"或者实数十进制。
答案 2 :(得分:1)
这是没有功能和存储过程的解决方案 - 只是为了它的乐趣。首先,您必须创建新列(我称之为decimal
),然后使用以下查询将其填充为从原始混合格式列(称为inconsistent
)转换的值:
UPDATE "my_table"
SET "decimals" = CASE WHEN CHARINDEX('/', "inconsistent") > 0
THEN CAST(CASE WHEN CHARINDEX(' ',
RTRIM(LTRIM("inconsistent"))) > 0
THEN LEFT(RTRIM(LTRIM("inconsistent")),
CHARINDEX(' ',
RTRIM(LTRIM("inconsistent")))
- 1)
ELSE '0'
END AS FLOAT)
+ CAST(SUBSTRING(RTRIM(LTRIM("inconsistent")),
CHARINDEX(' ',
RTRIM(LTRIM("inconsistent")))
+ 1,
CHARINDEX('/',
RTRIM(LTRIM("inconsistent")))
- 1 - CHARINDEX(' ',
RTRIM(LTRIM("inconsistent")))) AS FLOAT)
/ CAST(RIGHT(RTRIM(LTRIM("inconsistent")),
LEN(RTRIM(LTRIM("inconsistent")))
- CHARINDEX('/',
RTRIM(LTRIM("inconsistent")))) AS FLOAT)
ELSE CAST(RTRIM(LTRIM("inconsistent")) AS FLOAT)
END
答案 3 :(得分:0)
我不知道任何数据库系统或代码框架,本身支持6 11/32
等字符串。最好的办法是在相关表中添加一列,并使用脚本对其中的实际值进行反规范化,或者在其上创建一个自动执行该操作的视图。虽然它会采用一些复杂的代码,但在SQL中执行它可能不是一个好主意。