当源自excel的数据中存在各种特殊字符时,将varchar转换为十进制

时间:2015-12-16 17:46:02

标签: excel tsql sql-server-2012

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

我想创建一个清除特殊字符并返回十进制数据类型的函数。这似乎是我应该面对和解决这个问题的许多人,我要求最好的方法来实现这一目标。

以下是我目前面临的一个小清单,我想知道除了 ($, - )领先空间,跟踪空间之外是否还有其他字符我应该考虑(S)

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

下面是我正在努力帮助开发该函数的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

4 个答案:

答案 0 :(得分:1)

以前在Excel中使用格式化的货币字符串。然后开发人员提到了SQL Server 2012中引入的TRY_PARSE

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

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

您不应该使用money因为所有计算都会舍入到2位小数,即使在中间步骤中也是如此。在这里,它仅用于方便。

答案 1 :(得分:0)

以下是更正的功能:

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)')
*/

END

答案 2 :(得分:0)

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

/********************************************************************************************************
      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穿上防火服并等待回复。

答案 3 :(得分:0)

这是基于JAC输入的另一种解决方案。

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

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