Oracle SQL - REGEXP_LIKE 在 CHECK 约束中没有按预期工作

Posted

技术标签:

【中文标题】Oracle SQL - REGEXP_LIKE 在 CHECK 约束中没有按预期工作【英文标题】:Oracle SQL - REGEXP_LIKE not working as expected in CHECK constraint 【发布时间】:2020-10-24 04:27:41 【问题描述】:

我正在使用 Oracle SQL,并且我想添加一个 CHECK 约束,以便在创建表时检查正则表达式。但是,REGEXP_LIKE 函数的行为与在线 RegEx 测试工具不同。

假设我想创建一个名为Testing 的表,其中只有一个名为roomNo 的属性。我希望roomNo 只存储 4 个数字,可选地后跟一个大写字母(例如,12341234A):

CREATE TABLE Testing (
    roomNo      char(5),
    CONSTRAINT check_roomNo CHECK (REGEXP_LIKE(roomNo, '^\d4[A-Z]?$'))
);
insert into Testing values ('1234X');
insert into Testing values ('1234');  -- Unexpected error here

当我运行这个脚本时,我可以成功地将1234X 插入到表中,但是Oracle SQL 在插入1234 时会抛出一个错误:

Error starting at line : 5 in command -
insert into Testing values ('1234')
Error report -
ORA-02290: check constraint (USER.CHECK_ROOMNO) violated

我不太明白为什么这是一个错误,因为当我在在线 RegEx 测试工具中测试 RegEx ^\d4[A-Z]?$ 时,它可以匹配 1234X1234。 Here is a link 到使用我在 REGEXP_LIKE 函数中使用的 RegEx 的 RegEx 测试工具。非常感谢!

【问题讨论】:

【参考方案1】:

经过一番挖掘,我发现roomNo的数据类型为char(5)是这个问题的罪魁祸首。

根据charin here上的Oracle文档:

当您将字符值插入 CHAR 数据库列时,Oracle 不会去除尾随空格。如果值小于列的定义宽度,Oracle 将值填充到定义的宽度

当我在表中插入1234 时,由于1234 的长度比列的定义宽度短(即宽度为5),Oracle 在字符串的右侧添加空白填充,以便字符串存储为1234 1234 后面有一个空格。

因此,字符串1234 无法匹配正则表达式^\d4[A-Z]?$,因为字符串的最后一个字符(即空格)不匹配[A-Z]

我能想到的一个解决方案是使用^\d4[A-Z ]?$ 的正则表达式,以便它可以匹配位于第 5 个字符的单个空格。

编辑:

另一种解决方案是使用RTRIM()函数去除右边的拖尾空格:

CONSTRAINT check_roomNo CHECK (REGEXP_LIKE(RTRIM(roomNo), '^\d4[A-Z]?$'))

【讨论】:

有;由于值的长度不固定为 5 个字符,请切换到 VARCHAR2 数据类型。 这也是我的第一个想法。 char 只是麻烦 - 我的建议是避免它,除非您确实需要将尾随空格附加到较短的值。我无法想象为什么有人会想要附加尾随空格。

以上是关于Oracle SQL - REGEXP_LIKE 在 CHECK 约束中没有按预期工作的主要内容,如果未能解决你的问题,请参考以下文章

oracle -sql模式匹配

Oracle SQL - REGEXP_LIKE 包含字符串“NA”以外的字符

Oracle:Oracle 8i 中 REGEXP_LIKE 函数的替代方案

Oracle 正则表达式函数-REGEXP_LIKE 使用例子

Oracle中REGEXP_LIKE与LIKE的区别

oracle 判断字段是否为是数字等 regexp_like用法 正则表达式