在源自Excel的数据中存在各种特殊字符时,将varchar转换为小数

我有一个从Excel导入CSV文件。 由于需要保留原始值,因此所有值都以varcharforms导入。 现在我需要将货币值转换为十进制(18,4)。 然而,许多行包含特殊字符(请参阅下面的简短列表)。

我想创build一个函数来清理特殊字符并返回一个十进制数据types。 这似乎很多之前我应该​​面对和解决这个问题,我要求最好的方法来完成这一点。

这里是我目前所面临的一个小列表,想知道除了($, – )领先空间,足迹空间之外,还有其他angular色应该考虑:

$634,375.00 (104,055.00) -139,686.03 (72,631.45) 17774137.14 8374187.29 $-7041078.47 

以下是我正在致力于帮助开发该function的一个select语句:

 SELECT i.[AsOfDate] ,COALESCE(case when len(ltrim(rtrim(i.[DealNum])))= 0 then null else i.[DealNum] end, case when len(ltrim(rtrim(i.[CUSIP])))= 0 then null else i.[CUSIP] end, case when len(ltrim(rtrim(i.[PoolNum])))= 0 then null else i.[PoolNum] end) AS [DealNum_CusIP_PoolNum] ,case when isnumeric(i.[Coupon]) = 1 then cast(i.[Coupon] as decimal(18,4)) else 0 end as [Coupon] ,case when isdate(i.[PurchaseDate]) = 1 then cast(i.[PurchaseDate] as date) else null end as [PurchaseDate] ,case when isdate (i.[SettleDate]) = 1 then cast(i.[SettleDate] as date) else null end as [SettleDate] ,case when isnumeric(Replace(Replace(ltrim(rtrim(i.[CurrentFace])),'(','-'),')','')) = 1 then cast(Replace(Replace(ltrim(rtrim(i.[CurrentFace])),'(','-'),')','') as decimal(18,4)) else 0 end as [CurrentFace] ,case when isnumeric(i.[PurchasePrice]) = 1 then cast(i.[PurchasePrice] as decimal(18,4)) else 0 end as [PurchasePrice] ,case when isnumeric(i.[CurrentPrice]) = 1 then cast(i.[CurrentPrice] as decimal(18,4)) else 0 end as [CurrentPrice] ,case when isnumeric(i.[RealizedGL]) = 1 then cast(i.[RealizedGL] as decimal(18,4)) else 0 end as [RealizedGL] ,case when isnumeric(Replace(i.[Premium],'$','')) = 1 then cast(Replace(i.[Premium],'$','') as decimal(18,4)) else 0 end as [Premium] ,case when isnumeric(i.[OLMTM]) = 1 then cast(i.[OLMTM] as decimal(18,4)) else 0 end as [OLMTM] ,case when isnumeric(i.[CurrentMTM]) = 1 then cast(i.[CurrentMTM] as decimal(18,4)) else 0 end as [CurrentMTM] FROM [import].[Openlink_Position_Detail] I 

这是我到目前为止,但它仍然不完全工作:

 CREATE FUNCTION Stage.CleanForDecimal ( @input varchar(100) ) RETURNS decimal(18,4) AS BEGIN DECLARE @rv as decimal(18,2), @wv as varchar(100) SELECT @wv = ltrim(rtrim(@input)); SELECT @wv = replace(@input,'$',''); SELECT @wv = replace(@input,',',''); SELECT @wv = replace(@input,'(','-'); SELECT @wv = replace(@input,')',''); SELECT @rv = case when isnumeric(@wv) = 1 then cast(@wv as decimal(18,4)) else 0 end -- Return the result of the function RETURN @rv END 

它曾经是在Excel中格式化的货币string。 然后,开发人员提到在SQL Server 2012中引入的TRY_PARSE

 CAST(TRY_PARSE(MyColumn AS money USING 'en-US') AS float) 

这适用于空格,美元符号,逗号和括号。 它适用于您提供的所有样本数据,但不能用欧元符号作为例子。

您不应该使用money因为所有计算都舍入到小数点后两位,即使在中间步骤中也是如此。 这里只是为了方便。

这是更正的function:

 ALTER FUNCTION [Stage].[CleanForDecimal] ( @input varchar(100) ) RETURNS decimal(18,4) AS BEGIN DECLARE @rv as decimal(18,4), @wv as varchar(100) SELECT @wv = ltrim(rtrim(@input)); SELECT @wv = replace(@wv,'$',''); SELECT @wv = replace(@wv,',',''); SELECT @wv = replace(@wv,'(','-'); SELECT @wv = replace(@wv,')',''); SELECT @rv = case when isnumeric(@wv) = 1 then cast(@wv as decimal(18,4)) else 0 end RETURN @rv /* execution example: select Stage.CleanForDecimal(' ($123,44.2345)') */ 

结束

FWIW这里是针对同样问题的Oracle解决scheme。 当然,你不能按原样使用它,但也许你可以使用我们如何解决问题的逻辑。 信息就是力量!

 /******************************************************************************************************** Name: STR_TO_NUMBER Desc: Converts a string to a number, stripping dollar signs, commas and converting if a negative is shown by parentheses. Used when converting data froma spreadsheet where the format shows negatives in parens. Args: string_in IN VARCHAR2 Returns: NUMBER Usage: SELECT thc_utl.str_to_number('(1,234.56)') FROM dual; REVISIONS: Ver Date Author Description --------- ---------- --------------- ------------------------------------ 1.0 12/12/2014 Gary_W - Created function. ************************************************************************************************************************/ FUNCTION STR_TO_NUMBER(string_in IN VARCHAR2) RETURN NUMBER AS v_nbr NUMBER; BEGIN -- TRIM the string, then -- strip commas with REPLACE() -- strip dollar signs with REPLACE() -- then take what's in the parens, add a negative sign and make it a number. v_nbr := to_number(regexp_replace(replace(replace(TRIM(string_in),','),'$'), '^\(([^)]+)\)$', '-\1')); RETURN v_nbr; -- Return the converted number. END STR_TO_NUMBER; 

Gary_W穿上防火服,等待回复。

这是根据江淮投入的另一个解决scheme。

 declare @somestring as varchar(100) set @somestring = ' ($123,234.5567)' Select isnull(CAST(TRY_PARSE(@somestring AS money USING 'en-US') AS decimal(18,4)),0) as rv -- returns -123234.5567 set @somestring = ' ($123,2fubar34.5567)' Select isnull(CAST(TRY_PARSE(@somestring AS money USING 'en-US') AS decimal(18,4)),0) as rv -- returns 0.0000 

我不确定这是否比我之前发布的函数更有效,但是我希望它能帮助其他人解决这个问题。