如何过滤掉 teradata 文本字段中的非数字值?
Posted
技术标签:
【中文标题】如何过滤掉 teradata 文本字段中的非数字值?【英文标题】:how do i filter out non-numeric values in a text field in teradata? 【发布时间】:2011-04-03 08:21:08 【问题描述】:o我有一个包含大约 1000 万条记录的 teradata 表,它将数字 id 字段存储为 varchar。我需要将此字段中的值传输到另一个表中的 bigint 列,但我不能简单地说 cast(id_field as bigint) 因为我收到无效字符错误。查看这些值,我发现字符串中的任何位置都可能有一个字符,所以假设字符串是 varchar(18) 我可以像这样过滤掉无效行:
where substr(id_field,1,1) not in (/*big,ugly array of non-numeric chars*/)
and substr(id_field,2,1) not in (/*big,ugly array of non-numeric chars*/)
etc, etc...
然后演员表会起作用,但从长远来看这是不可行的。它很慢,如果字符串有 18 个可能的字符,它会使查询不可读。如果不单独检查每个字符以查找非数字字符数组,我如何过滤掉该字段中具有不会强制转换为 bigint 的值的行?
示例值为
123abc464
a2.3v65
a_356087
........
000000000
BOB KNIGHT
1235468099
这些值没有特定的模式,我只需要过滤掉那些包含任何非数字数据的值。 123456789 可以,但是 123.abc_c3865 不行……
【问题讨论】:
请提供一些例子。你的意思是你有这样的数据? 123abc456 那你叫数字id字段吗? 【参考方案1】:从TD14 Teradata开始添加了一些功能,现在有多种方式,例如:
WHERE RTRIM(col, '0123456789') = ''
但最简单的方法是 TO_NUMBER,它对坏数据返回 NULL:
TO_NUMBER(col)
【讨论】:
【参考方案2】:我曾经管理过的最好的是:
where char2hexint(upper(id_field)) = char2hexint(lower(id_field))
由于大写字符与小写字符的十六进制值不同,这将确保您没有字母字符,但仍会留下下划线、冒号等。如果这不符合您的要求,您可能需要编写一个 UDF。
【讨论】:
不幸的是,我必须处理特殊字符。什么是 UDF? 用户定义函数,用 C 编写。developer.teradata.com/blog/madmac/2010/03/… 有一个用于检查 BigInts 的函数 更新链接:downloads.teradata.com/blog/madmac/2010/03/…【参考方案3】:我们是否也可以尝试将字段中的值除以某个整数“如果除则必须是一个数字,如果不是并抛出一些错误,则必须有一些字符......”猜想这会很快只涉及数学...
【讨论】:
这种方法的问题在于,Teradata 不会告诉您哪些行包含此失败的字符。它只是说有一个失败。如何找到特定行以便解决问题?【参考方案4】:我在尝试从街道地址门牌号码中排除字母字符时遇到了同样的问题。如果您不介意将所有数字连接在一起,以下将起作用...... 它检查字符串的上限是否等于字符串的下限,如果是,则为数字,否则为空。
select cast(case when upper(substring('12E'from 1 for 1)) = lower(substring('12E'from 1 for 1)) then substring('12E'from 1 for 1) else null end ||
case when upper(substring('12E'from 2 for 1)) = lower(substring('12E'from 2 for 1)) then substring('12E'from 2 for 1) else null end ||
case when upper(substring('12E'from 3 for 1)) = lower(substring('12E'from 3 for 1)) then substring('12E'from 3 for 1) else null end ||
case when upper(substring('12E'from 4 for 1)) = lower(substring('12E'from 4 for 1)) then substring('12E'from 4 for 1) else null end ||
case when upper(substring('12E'from 5 for 1)) = lower(substring('12E'from 5 for 1)) then substring('12E'from 5 for 1) else null end ||
case when upper(substring('12E'from 2 for 1)) = lower(substring('12E'from 2 for 1)) then substring('12E'from 2 for 1) else null end
as integer)
【讨论】:
这是与已接受答案类似的解决方案。但是,同样的问题仍然存在。你如何处理特殊字符?【参考方案5】:尝试使用此代码段
WHERE id_Field NOT LIKE '%[^0-9]%'
【讨论】:
Teradata 不进行正则表达式处理。至少不是我当时正在进行的实施。当然,这会让事情变得容易得多。 TD14添加了一些基于正则表达式的函数:WHERE REGEXP_SIMILAR(id_field , '[0-9]') = 1
,在TD14之前可能有oTRANSLATE:WHERE oTranslate('id_field', '0123456789','') = ''
【参考方案6】:
我发现 lins314159 回答对类似问题非常有帮助。这可能是一个旧线程,但为了它的价值,我使用了:
char2hexint(upper(id_field)) = char2hexint(lower(id_field)) AND substr(id_field,1,1) IN ('1' to '9')
成功地将剩余的 VARCHAR 结果转换为 INT
【讨论】:
【参考方案7】:SELECT customer_id
FROM t
WHERE UPPER(customer_id)(CASESPECIFIC) <>
LOWER(customer_id)(CASESPECIFIC);
这可以很好地检查数字字段中的值是否为非数字。
【讨论】:
不,它只适用于存在大写/小写字母的字符:试试1<23
或1ß23
【参考方案8】:
SELECT id_field
WHERE oTranslate(id_field, '0123456789','')<>'';
这对我很有效!它显示任何包含非数字值的 id_field
【讨论】:
以上是关于如何过滤掉 teradata 文本字段中的非数字值?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Teradata SQL 中使用 LEFT JOIN 对查询中的非聚合参数进行 GROUP BY?