在SQL列中使用仅数字数据过滤行

时间:2014-01-20 12:00:27

标签: sql regex oracle

我正在尝试在表格中SELECT行,通过应用仅识别数字列的过滤条件。这是一个仅报告查询,因此我们最不需要打扰性能,因为我们没有权限编译PL / SQL,无法通过TO_NUMBER()检查并返回它是否为数字。

我必须在SQL中实现它。此列也具有这样的值,必须将其视为数字。

-1.0
-0.1
-.1
+1,2034.89
+00000
1023

经过深思熟虑的研究,我写了这篇文章。(困难时期)

  WITH dummy_data AS
  ( SELECT '-1.0' AS txt FROM dual
  UNION ALL
  SELECT '+0.1' FROM dual
  UNION ALL
  SELECT '-.1' FROM dual
  UNION ALL
  SELECT '+1,2034.89.00' FROM dual
  UNION ALL
  SELECT '+1,2034.89' FROM dual
  UNION ALL
  SELECT 'Deva +21' FROM dual
  UNION ALL
  SELECT '1+1' FROM dual
  UNION ALL
  SELECT '1023' FROM dual
  )
SELECT dummy_data.*,
  REGEXP_COUNT(txt,'.')
FROM dummy_data
WHERE REGEXP_LIKE (TRANSLATE(TRIM(txt),'+,-.','0000'),'^[-+]*[[:digit:]]');

我明白了。

TXT           REGEXP_COUNT(TXT,'.')
------------- ---------------------
-1.0                              4
+0.1                              4
-.1                               3
+1,2034.89.00                    13 /* Should not be returned */
+1,2034.89                       10
1+1                               3 /* Should not be returned */
1023                              4

7 rows selected.

现在非常混淆2个问题。

1)我的结果也是+1,2034.89.00,我应该消除它。 (表示两位小数)不仅是小数点,还应该消除每个其他特殊字符( - +,)的双倍)

2)为了更加丑陋,计划做REGEXP_COUNT('.') <= 1。但它并没有回归我的期望,在选择时,我看到了奇怪的价值回归。

有人可以帮我构建REGEXP以避免('.','+','-')

的双重出现

3 个答案:

答案 0 :(得分:1)

首先你用翻译删除加号和减号然后你想知道为什么不考虑他们的位置? : - )

这应该有效:

WITH dummy_data AS
  ( SELECT '-1.0' AS txt FROM dual
  UNION ALL
  SELECT '+0.1' FROM dual
  UNION ALL
  SELECT '-.1' FROM dual
  UNION ALL
  SELECT '+12034.89.00' FROM dual -- invalid: duplicate decimal separator 
  UNION ALL
  SELECT '+1,2034.89' FROM dual -- invalid: thousand separator placement
  UNION ALL
  SELECT 'Deva +21' FROM dual -- invalid: letters
  UNION ALL
  SELECT '1+1' FROM dual -- invalid: plus sign placement
  UNION ALL
  SELECT '1023' FROM dual
  UNION ALL
  SELECT '1.023,88' FROM dual -- invalid: decimal/thousand separators mixed up
  UNION ALL
  SELECT '1,234' FROM dual
  UNION ALL
  SELECT '+1,234.56' FROM dual
  UNION ALL
  SELECT '-123' FROM dual
  UNION ALL
  SELECT '+123,0000' FROM dual -- invalid: thousand separator placement
  UNION ALL
  SELECT '+234.' FROM dual -- invalid: decimal separator not followed by digits
  UNION ALL
  SELECT '12345,678' FROM dual -- invalid: missing thousand separator
  UNION ALL
  SELECT '+' FROM dual -- invalid: digits missing
  UNION ALL
  SELECT '.' FROM dual -- invalid: digits missing
  )
select * from dummy_data
where regexp_like(txt, '[[:digit:]]') and
(
  regexp_like(txt, '^[-+]{0,1}([[:digit:]]){0,3}(\,([[:digit:]]){0,3})*(\.[[:digit:]]+){0,1}$')
  or 
  regexp_like(txt, '^[-+]{0,1}[[:digit:]]*(\.[[:digit:]]+){0,1}$')
);

你看,你需要三个正则表达式;一个用于保证字符串中至少有一个数字,一个用于包含千位分隔符的数字,另一个用于没有数字的数字。

有千位分隔符:txt可能以一个加号或减号开头,那么最多可能有三个数字。这些可以跟随一千个分隔符加三个数字几次。然后可能会有一个小数分隔符,其中至少有一个跟随的数字。

没有千位分隔符:txt可能以一个加号或减号开头,然后可能有数字。然后可能会有一个小数分隔符,其中至少有一个跟随的数字。

我希望我没有忽视任何事情。

答案 1 :(得分:1)

以下表达式适用于除逗号外的所有内容:

'^[-+]*[0-9,]*[.]*[0-9]+$'

您可以使用以下附加检查检查错误的逗号位置:

not regexp_like(txt, '[-+]*,$') and not regexp_like(txt, [',,'])

答案 2 :(得分:0)

我只是试图纠正你的错误并尽可能简化SQL。但不整齐!

WITH dummy_data AS
  ( SELECT '-1.0' AS txt FROM dual
  UNION ALL
  SELECT '+.0' FROM dual
  UNION ALL
  SELECT '-.1' FROM dual
  UNION ALL
  SELECT '+1,2034.89.0' FROM dual
  UNION ALL
  SELECT '+1,2034.89' FROM dual
  UNION ALL
  SELECT 'Deva +21' FROM dual
  UNION ALL
  SELECT 'DeVA 234 Deva' FROM dual
  UNION ALL
  SELECT '1023' FROM dual
  )
SELECT to_number(REPLACE(txt,',')),
  REGEXP_COUNT(txt,'.')
FROM dummy_data
WHERE REGEXP_LIKE (txt,'^[-+]*')
AND NOT REGEXP_LIKE (TRANSLATE(txt,'+,-.','0000'),'[^[:digit:]]')
AND REGEXP_COUNT(txt,',')  <= 1
AND REGEXP_COUNT(txt,'\+') <= 1
AND REGEXP_COUNT(txt,'\-') <= 1
AND REGEXP_COUNT(txt,'\.') <= 1;