我有这个代码(已经存在,不是我的):
SELECT
a.id_original_contrato AS contrato,
( CASE WHEN d.value~'^\\d+$' THEN d.value::integer ELSE 0 END ) AS monto,
EXTRACT(YEAR FROM b.value)::integer AS anoinicio,
EXTRACT(YEAR FROM c.value)::integer AS anofin
......等(一些JOIN和WHERE)
让我解释一下:d.value
来自一个值为character varying (200)
的表。代码稍后将d.value
(现在称为“monto”)作为integer
插入到另一个表中。有人为了提取一些字符而编码了正则表达式,或者在其他情况下(ELSE),将其定义为0.这些值仅在integer
时起作用。如果我使用像76.44
那样的d.value,由于正则表达式不起作用,它总是将其定义为0.。
好吧,我必须更改该代码,因为:
numeric
存储在新表中,而不再存储为integer
(在我的新表中,数据类型现在为numeric
)76.44
或66,56
(点或昏迷)。我不确定正则表达式在做什么。我怎样才能用更好的或新的正则表达式来完成什么需要?
答案 0 :(得分:2)
选择变体:
with v(value) as (
values
('12,3'),
('12.3'),
('123'),
('123.'),
('.123'),
('1.2.3')
)
select
value,
value ~ '^(\d+[,\.]\d+|\d+)$' as variant_a,
value ~ '^(\d*[,\.]\d*|\d+)$' as variant_b,
value ~ '^\d+[,\.]\d+$' as variant_c
from v;
value | variant_a | variant_b | variant_c
-------+-----------+-----------+-----------
12,3 | t | t | t
12.3 | t | t | t
123 | t | t | f
123. | f | t | f
.123 | f | t | f
1.2.3 | f | f | f
(6 rows)
要将带点或逗号的字符串转换为数字,请使用replace()
:
select replace(value, ',', '.')::numeric;
答案 1 :(得分:2)
您应该声明Postgres的版本以及编写代码时使用的版本(如果您知道的话)。 \\d
中的双反斜杠表示旧版本standard_conforming_strings = off
。 The manual:
从PostgreSQL 9.1开始,默认值为
on
(之前的版本默认为关闭)。
在standard_conforming_strings = on
的现代版本中,此字符串作为正则表达式毫无意义: 。要检测由一个或多个数字组成的字符串,请使用'^\\d+$'
E'^\\d+$'
(前缀为E
)或'^\d+$'
。详细说明:
整数文字还允许可选的前导符号表示负数/正数。在Postgres中也允许(自动修剪)前导/悬空空格
所以,这是integer
的完整正则表达式:
CASE WHEN d.value ~ '^\s*[-+]?\d+\s*$' THEN d.value::int ELSE 0 END
正则表达式解释说:
^
..开头的字符串
\s
class shorthand [[:space:]]
(空格)
*
.. quantifier 0次或更多次
[+-]
..由+
和-
组成的字符类
?
..量词为0或1次
\d
.. [[:digit:]]
(数字)的简写类
+
..量词为1次或更多次
\s*
..与上述相同
$
..字符串结尾
现在我们了解基础知识。阅读我链接到的手册中的更多内容。考虑numeric string literals的语法规则。而且,关于合法数字常数的状态:
常量
中不能嵌入任何空格或其他字符
那是因为没有引用数字常量,因此无法使用空格。不适用于投射字符串。空白容忍: 在指数char之后的前导,尾随和右边。
所以这些都是演员numeric
的合法字符串:
<强> '^\s*[-+]?\d*\.?\d+(?:[eE]\s*[-+]?\d+)?\s*$'
强>
唯一的新元素是parentheses (()
) to denote the contained regular expression as atom。由于我们对反向引用不感兴趣,请使用“非捕获”:(?:
... )
并附加问号(?:[eE]\s*[-+]?\d+)?
表示:可以添加“指数”部分或不,作为一个整体。
假设点(.
)为小数点分隔符。您可以使用逗号(,
)或[,\.]
来允许。但是只有点才对演员合法。
测试:
SELECT '|' || txt || '|' As text_with_delim
, txt ~ '^\s*[-+]?\d*\.?\d+([eE]\s*[-+]?\d+)?\s*$' As test
, txt::numeric AS number
FROM unnest ('{1, 123, 000, " -1 ", +2, 1.2, .34, 5e6, " .5e -6 "}'::text[]) txt;
结果:
text_with_delim | test | number
-----------------+------+-----------
|1| | t | 1
|123| | t | 123
|000| | t | 0
| -1 | | t | -1
|+2| | t | 2
|1.2| | t | 1.2
|.34| | t | 0.34
|5e6| | t | 5000000
| .5e -6 | | t | 0.0000005
或者您可以使用to_number()
转换任意给定格式的字符串。