从精美的数组运算符手册中:
运算符:@>
描述:包含
示例:ARRAY[1,4,3] @> ARRAY[3,1]
结果:t
(AKA true)
因此@>
将其操作数数组视为集合并检查右侧是否是左侧的子集。
IN
有点不同,与子查询一起使用:
9.22.2。在
expression IN (subquery)
右边是一个带括号的子查询,它必须只返回一列。评估左侧表达式并将其与子查询结果的每一行进行比较。如果找到任何相等的子查询行,则结果IN
为“真”。如果没有找到相等的行,则结果为“假”(包括子查询不返回任何行的情况)。
或使用文字列表:
9.23.1。在
expression IN (value [, ...])
右侧是标量表达式的括号列表。如果左侧表达式的结果等于任何右侧表达式,则结果为“真”。这是一个简写符号
expression = value1
OR
expression = value2
OR
...
所以a IN b
或多或少意味着:
该值是否a
等于列表中的任何值b
(可以是生成单个元素行的查询或文字列表)。
当然,你可以这样说:
array[1] in (select some_array from ...)
array[1] in (array[1], array[2,3])
但是这些情况下的数组仍然被视为单个值(恰好具有一些内部结构)。
如果您想检查一个数组是否包含任何值列表,那么@>
这不是您想要的。考虑一下:
array[1,2] @> array[2,4]
4
is not inarray[1,2]
所以array[2,4]
不是 的子集array[1,2]
。
如果您想检查某人是否同时具有这两个角色,那么:
roles @> array['as_champion', 'whatever']
是正确的表达式,但如果您想检查是否roles
是这些值中的任何一个,那么您需要重叠运算符 ( &&
):
roles && array['as_champion', 'whatever']
请注意,我在任何地方都对数组使用“数组构造函数”语法,这是因为使用知道在替换占位符时将数组扩展为逗号分隔列表的工具(例如 ActiveRecord)更方便,但是不完全理解 SQL 数组。
鉴于这一切,我们可以说:
Membership.where('roles @> array[?]', %w[as_champion whatever])
Membership.where('roles @> array[:roles]', :roles => some_ruby_array_of_strings)
一切都会按预期进行。您仍在使用少量 SQL 片段(因为 ActiveRecord 对 SQL 数组或任何表示@>
运算符的方式没有完全理解),但至少您不必担心引用问题。您可能可以通过 AREL 手动添加@>
支持,但我发现 AREL 很快就会变成一个难以理解和难以理解的混乱,除了最微不足道的用途。