在Teradata中安全地将VARCHAR转换为DECIMAL

时间:2012-04-18 12:00:16

标签: casting decimal varchar teradata isnumeric

在Teradata DB中我有源表

create set table SRC_TABLE (
    Some_Id varchar(2O) not null
);

此表加载了来自外部系统的数据。我有目标表

create set table DST_TABLE (
    Some_Id decimal(4,0) not null
);

我需要安全地将行从SRC_TABLE复制到DST_TABLE。有一个合同,外部系统将只提供可转换为DECIMAL(4)的值。但是,有没有安全的方法如何在SRC_TABLE中选择不符合合同的行并可能导致类型转换失败?

更新:由于我正在处理的环境限制,我无法使用UDF功能。

3 个答案:

答案 0 :(得分:0)

我建议在SQL中使用错误表中的MERGE INTO操作来捕获无法应用的记录。这将允许您加载数据并对无法应用的错误表中的记录进行后处理。

您还可以从Teradata Developer Exchange下载相应的UDF库,并使用IsNumeric()等效项对SRC_TABLE的每一行执行条件检查,以避免将非数字数据插入表中。此条件检查可以丢弃整个记录,将记录加载到日志表,或将值设置为无效数据的约定默认值。

CREATE ERROR TABLE MyDB.TGT_TABLE_ERR FOR MyDB.TGT_TABLE; -- Creates Error Table for MERGE INTO operation

MERGE INTO MyDB.TGT_TABLE T1
     USING MyDB.SRC_TABLE T2
        ON T1.{primary index} = T2.{primary index}
WHEN MATCHED THEN
     UPDATE SET Some_ID = CAST(T2.Some_ID AS DECIMAL(4,0))
WHEN NOT MATCHED THEN
     INSERT VALUES (T2.{column list})
LOGGING ALL ERRORS WITH NO LIMIT;

答案 1 :(得分:0)

您可以使用FastExport从旧表中写出数据,然后使用FastLoad将其加载到新表中。任何解析为十进制(4,0)的记录都将加载到新表中,而其余记录将写入错误表。确保设置足够高的ERRLIMIT以确保在发生一些错误后作业不会死亡。

答案 2 :(得分:-1)

最后在同事的帮助下,我找到了可行的解决方案。它有一些限制(不考虑符号,不考虑小数部分),但对于ID它可以正常工作。

  1. 修剪字符串开头和结尾的空格
  2. 修剪字符串
  3. 的前导零
  4. 测试最大允许长度
  5. 将零字符串填充到四个字符(将四个零添加到字符串的开头并从字符串中获取最后四个字符)
  6. 在允许的字符集上测试字符串中的每个位置
  7. 因此,可以通过选择获取SRC_TABLE中无法转换为DECIMAL(4)的记录:

    select 
      Some_Id
    from
      SRC_TABLE
    where
      characters(trim(leading '0' from trim(both ' ' from Some_Id))) > 4
      or substring(substring('0000' || trim(leading '0' from trim(both ' ' from Some_Id)) FROM characters('0000' || trim(leading '0' from trim(both ' ' from Some_Id))) - 3) FROM 1 FOR 1) NOT IN ('0','1','2','3','4','5','6','7','8','9')  
      or substring(substring('0000' || trim(leading '0' from trim(both ' ' from Some_Id)) FROM characters('0000' || trim(leading '0' from trim(both ' ' from Some_Id))) - 3) FROM 2 FOR 1) NOT IN ('0','1','2','3','4','5','6','7','8','9')
      or substring(substring('0000' || trim(leading '0' from trim(both ' ' from Some_Id)) FROM characters('0000' || trim(leading '0' from trim(both ' ' from Some_Id))) - 3) FROM 3 FOR 1) NOT IN ('0','1','2','3','4','5','6','7','8','9')
      or substring(substring('0000' || trim(leading '0' from trim(both ' ' from Some_Id)) FROM characters('0000' || trim(leading '0' from trim(both ' ' from Some_Id))) - 3) FROM 4 FOR 1) NOT IN ('0','1','2','3','4','5','6','7','8','9');
    

    编辑: 更方便的是dnoeth在回答Convert char to int TeraData Sql时提出的方法,这也适用于TD 13.10:

    -- TO_NUMBER returns NULL when failing
    
    CAST(TO_NUMBER(UTENTE_CD) AS INTEGER)
    
    -- check if there are only digits
    CASE WHEN UTENTE_CD  = ''                     -- all spaces
           THEN NULL
         WHEN LTRIM(UTENTE_CD, '0123456789') = '' -- only digits
           THEN CAST(UTENTE_CD AS INTEGER)
         ELSE NULL
    END