我正在尝试在表格中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
以避免('.','+','-')
答案 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;