TLDR
如何使用列值 ('input' ~ t.somecolumn
) 进行正则表达式匹配查询,其中只有已知的行子集在该列中具有有效的正则表达式?
完整示例
- 有一个
blocked_items
表,包括两个 varchar 列:type
和value
, - 其中一种类型是
DOMAIN_REGEX
,然后value
始终包含正确的正则表达式, - 但是:对于其他类型的
value
不需要是正则表达式,当被视为正则表达式时可能会导致错误。
为了检查域是否被阻止,我调用此查询并将有问题的 URL 作为参数传递$1
:
SELECT 1 FROM blocked_items WHERE type = 'DOMAIN_REGEX' AND $1 ~ value LIMIT 1
问题:在某些数据库实例上,如果具有另一个type
的行具有value
不是有效的正则表达式,则查询将失败。在一个数据库上,此查询正常运行,而在另一个实例上,无论输入如何,都会抛出:invalid regular expression: quantifier operand invalid
。
示例测试数据:
| type | value |
|--------------+---------------------|
| EMAIL | test+++1@test.com |
| DOMAIN_REGEX | testd.com |
问题
我知道我的错误原因是数据库引擎可以选择首先检查第二个条件($1 ~ value
)——我已经检查了查询的EXPLAIN
,实际上这两个数据库实例是不同的。
有没有办法我可以
- 强制数据库先检查
type
列,所以正则表达式过滤器始终有效?
以 - 不同的方式形成查询以忽略非正则表达式
value
条目的错误?或者先检查它是否是有效的正则表达式? - 以另一种方式解决此问题?
我知道更改模式或使用LIKE
可能就足够了,但现在我偶然发现了这个,我很好奇是否有使用像这样的正则表达式的解决方案:)
您应该能够使用case
强制操作顺序:
SELECT 1
FROM blocked_items
WHERE (CASE WHEN type <> 'DOMAIN_REGEX' THEN false
ELSE $1 ~ value
END)
LIMIT 1;
通常,SQL(和Postgres)对表达式的求值顺序几乎没有控制。 但是,CASE
在许多情况下应提供这种控制。
你是对的,模式不是很好。如果您仍然必须保留架构,则可以尝试 CASE/WHEN,https://www.postgresqltutorial.com/postgresql-case/