PostgreSQL中=ANY与IN为何表现不同?实例解析
=ANY能匹配数组,IN却报错? 这个问题其实戳中了PostgreSQL对SQL标准扩展和语法糖实现的一个细节差异——虽然SQL标准里确实定义RVC IN IPV等价于RVC = ANY IPV,但这个等价关系是有前提的,咱们一步步拆解:
1. 标准SQL的等价场景有局限
SQL标准中,IN谓词的右边IPV只能是行值列表(比如(1,2,3))或者返回单列的子查询,这时候IN确实是=ANY的语法糖。但PostgreSQL对ANY操作符做了标准之外的扩展:它允许ANY直接作用于数组类型,自动遍历数组元素做比较。
2. 两个查询的本质差异
咱们看你的两个例子:
第一个查询:
select 'match' where 1 = any( string_to_array('1,2,3', ',')::int[])
PostgreSQL识别到ANY后面跟的是数组,会自动遍历数组中的每个整数元素,和左边的1逐一比较,只要有匹配就返回true,所以正常返回match。第二个查询:
select 'match' where 1 IN ( string_to_array('1,2,3', ',')::int[])
这里PostgreSQL并没有把数组展开成元素列表,而是把整个数组当作一个单独的“值”处理。相当于尝试执行1 = integer[]——整数和整数数组之间没有对应的比较操作符,自然就抛出了operator does not exist: integer = integer[]的错误。
3. 让IN和=ANY等价的方法
如果想让IN在这里实现和=ANY一样的效果,你需要把数组转换成PostgreSQL认可的行值集合,比如用unnest函数把数组拆成单行的结果集:
select 'match' where 1 IN (select unnest(string_to_array('1,2,3', ',')::int[]))
这时候IN的右边是子查询返回的单个列的行列表,符合标准SQL的IN语法,就能正常匹配了。
内容的提问来源于stack exchange,提问作者Lukasz Szozda

