PostgreSQL ~*运算符转换为Ecto语法的正确性与等效性问询
PostgreSQL ~* 运算符转Ecto写法的等效性说明
两种写法逻辑不完全等效,核心差异如下:
~*是PostgreSQL内置的不区分大小写正则匹配运算符,原SQLcol1 ~* 'AAA|bbb|CcC'的匹配规则是:只要col1字段值中包含AAA/bbb/CcC任意一个子串(匹配时忽略大小写)就命中,比如aAAxxx、xxBBByy这类包含目标子串的值都能匹配成功。- 你当前写的Ecto代码用无通配符的
ilike拼接OR条件,匹配规则是:col1字段值完全等于AAA/bbb/CcC其中一个(忽略大小写)才命中,比如只有AAA、aaa这类完全匹配的值能命中,xxAAA这类包含子串的值无法匹配,和原SQL逻辑不一致。
修正方案
方案1:保持OR拼接逻辑,对齐原SQL语义
如果要继续用ilike实现相同的子串匹配效果,需要给匹配值前后加通配符%:
from t1 in "table1", where: ilike(t1.col1, "%AAA%") or ilike(t1.col1, "%bbb%") or ilike(t1.col1, "%CcC%"), select: %{col1: t1.col1}
这种写法生成的SQL还是OR拼接形式,运行逻辑和原~*写法等价,但匹配目标字符串包含%/_等ilike特殊字符时需要额外转义。
方案2:直接调用~*运算符,和原SQL完全一致
用Ecto的fragment方法直接执行原生运算符,生成的SQL和你原始写法完全相同:
from t1 in "table1", where: fragment("? ~* ?", t1.col1, "AAA|bbb|CcC"), select: %{col1: t1.col1}
这种写法更简洁,性能也更优,但匹配目标字符串包含|/.等正则元字符时需要按正则规则转义。
补充说明
如果你的需求本身就是「不区分大小写完全匹配三个值其中一个」,那你当前的Ecto写法逻辑是正确的,只是和你给出的原SQL语义不同。
内容的提问来源于stack exchange,提问作者hnhl
相关产品推荐
相关产品推荐

