复杂的 postgresql 模式匹配

Complex postgresql pattern match

我在 postgres 中进行复杂的模式匹配查询时遇到了一些问题,我需要一些建议。

我有一个 table,其中有大约 55k 个带有项目代码的注册表,它们的模式具有以下规则:

  1. 必须始终以字母 CNF 开头
  2. "CNF" 字母后必须有一个 space
  3. 在 space 之后是一个必须始终为 8 个数字的数字序列
  4. 在第一个序列之后是另一个 space
  5. 在第二个 space 之后是另一个可以包含任意数量数字的序列。

这里有一些例子:

"CNF 56500155 99"
"CNF 51100039 3666"
"CNF 51100090 0985"
"CNF 52300021 07"
"CNF 52300020 4602"
"CNF 56700091 2515"
"CNF 56700091 387"
"CNF 56700091 4784"
"CNF 56500155 2066"
"CNF 56900149 6266"
"CNF 56300009 175"
"CNF 56700091 4782"
"CNF 51100084 2445"
"CNF 51100062 2379"
"CNF 52900014 0920"
"CNF 51100077 707"
"CNF 51100077 9706"
"CNF 51100101 6580"
"CNF 51500014 8929"
"CNF 56700091 79"
"CNF 51100090 8510"
"CNF 51100090 8508"
"CNF 51100090 8506"
"CNF 56700091 4774"
"CNF 51100101 9879"
"CNF 51100077 696"
"CNF 51100004 5083"
"CNF 56700091 4773"
"CNF 56500155 8616"
"CNF 51100039 324523423"
"CNF 51100090 5786"
"CNF 56700091 771"
"CNF 51100077 9692"
"CNF 51100077 9691"
"CNF 51500014 18928"
"CNF 56700091 24770"
"CNF 51100077 9685"

我想进行模式匹配查询以获取可能存在以下问题而不是所需模式的所有注册表。

    "CNF56500155 99" <-- No space between CNF and first sequence
    "CNF   51100039 3666" <-- Double or more spaces between CNF and first sequence
    "CNF 511000900985" <-- No space between first and second sequences
    "CNF 52300021     07" <-- Double or more spaces between first and second sequences
    "CNF 523000 07" <-- Less that eight numbers on the first sequence

我尝试了使用通配符和括号内字符的不同查询,但似乎找不到正确的查询,有人可以帮我吗?

代码应匹配正则表达式模式 ^CNF \d{8} \d+$,因此您应该 select 所有不匹配此模式的行,例如:

with codes(code) as (
values
    ('CNF 51100077 9692'),
    ('CNF 51100077 9691'),
    ('CNF 51500014 18928'),
    ('CNF 56700091 24770'),
    ('CNF 51100077 9685'),
    ('CNF56500155 99'),
    ('CNF   51100039 3666'),
    ('CNF 511000900985'),
    ('CNF 52300021     07'),
    ('CNF 523000 07')
)

select code
from codes
where code !~ '^CNF \d{8} \d+$';

        code         
---------------------
 CNF56500155 99
 CNF   51100039 3666
 CNF 511000900985
 CNF 52300021     07
 CNF 523000 07
(5 rows)    

Read about pattern matching with regular expressions.


附录。您可以在 table 上使用检查约束来防止插入与模式不一致的数据,例如

create table my_table (
    id int primary key, 
    code text
);

-- note that you can add this check constraint 
-- only if there are no rows which violate the condition
alter table my_table add check (code ~ '^CNF \d{8} \d+$');

insert into my_table
values (1, 'CNF 523000 07');

ERROR:  new row for relation "my_table" violates check constraint "my_table_code_check"
DETAIL:  Failing row contains (1, CNF 523000 07).