2

TL;DR@> {as_champion, whatever}我想知道使用is之间的优缺点是什么(或者它们是否相等)IN ('as_champion', 'whatever')。详情如下:

我正在使用 Rails 并使用 Postgres 的数组列类型,但是我的查询必须使用原始 sql,因为 Rails finder 方法不能很好地使用它。我找到了一种可行的方法,但想知道首选方法是什么:

roles表上的列是Memberships我的数组列。它是通过 rails 添加的:

add_column :memberships, :roles, :text, array: true

当我检查表格时,它显示的类型为:(text[]不确定这是否是 Postgres 真正表示数组列的方式,或者这是否是 Rails 的恶作剧。

要查询它,我会执行以下操作:

Membership.where("roles @> ?", '{as_champion, whatever}')
4

1 回答 1

8

从精美的数组运算符手册中:

运算符:@>
描述:包含
示例: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]

4is 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 很快就会变成一个难以理解和难以理解的混乱,除了最微不足道的用途。

于 2017-05-12T18:09:25.840 回答