自第 12 版以来 - 在撰写本文时是 2 年 + 4 个月前(但在我可以在接受的答案中看到的最后一次编辑之后),您可以 一次性使用GENERATED FIELD 很容易做到这一点,而不是每次您希望SELECT 一个新的po_number 时都必须计算它。
此外,您可以使用TRANSLATE 函数来提取您的数字,这比@ErwinBrandstetter 的REGEXP_REPLACE solution proposed 更便宜!
我会这样做(下面的所有代码都可以在小提琴here上找到):
CREATE TABLE s
(
num TEXT,
new_num INTEGER GENERATED ALWAYS AS
(NULLIF(TRANSLATE(num, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ. ', ''), '')::INTEGER) STORED
);
您可以酌情在TRANSLATE 函数中添加'ABCDEFG... 字符串 - 我在末尾有小数点 (.) 和一个空格 ( ) - 您可能希望那里有更多字符取决于您的输入!
并检查:
INSERT INTO s VALUES ('2'), (''), (NULL), (' ');
INSERT INTO t VALUES ('2'), (''), (NULL), (' ');
SELECT * FROM s;
SELECT * FROM t;
结果(两者相同):
num new_num
2 2
NULL
NULL
NULL
所以,我想检查我的解决方案的效率,所以我运行了以下测试,将 10,000 条记录插入到两个表 s 和 t 中,如下所示(来自 here):
EXPLAIN (ANALYZE, BUFFERS, VERBOSE)
INSERT INTO t
with symbols(characters) as
(
VALUES ('ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789')
)
select string_agg(substr(characters, (random() * length(characters) + 1) :: INTEGER, 1), '')
from symbols
join generate_series(1,10) as word(chr_idx) on 1 = 1 -- word length
join generate_series(1,10000) as words(idx) on 1 = 1 -- # of words
group by idx;
差异并没有那么大,但正则表达式解决方案始终慢了大约 25% - 甚至更改了经历 INSERTs 的表的顺序。
但是,TRANSLATE 解决方案真正出彩的地方是在执行“原始”SELECT 时,如下所示:
EXPLAIN (ANALYZE, BUFFERS, VERBOSE)
SELECT
NULLIF(TRANSLATE(num, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ. ', ''), '')::INTEGER
FROM s;
REGEXP_REPLACE 解决方案也是如此。
差异非常显着,TRANSLATE 大约需要。其他功能的 25% 的时间。最后,为了公平起见,我也对两张表都这样做了:
EXPLAIN (ANALYZE, BUFFERS, VERBOSE)
SELECT
num, new_num
FROM t;
两者都非常快速且相同!