查询Postgres数组列类型

mac*_*atz 2 postgresql ruby-on-rails ruby-on-rails-4 rails-activerecord array-column

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

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

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

add_column :memberships, :roles, :text, array: true
Run Code Online (Sandbox Code Playgroud)

当我检查表格时,它显示的类型为:(text[]不确定那是否是Postgres真正表示数组列的方式,还是那是Rails shenanigans。

要查询它,我要做类似的事情:

Membership.where("roles @> ?", '{as_champion, whatever}')
Run Code Online (Sandbox Code Playgroud)

mu *_*ort 5

从优良的Array Operators手册中

运算符:@>
说明:包含
示例:ARRAY[1,4,3] @> ARRAY[3,1]
结果:(t又名true)

因此,@>将其操作数数组视为集合,并检查右侧是否为左侧的子集。

IN有点不同,并且用于子查询

9.22.2。在

expression IN (subquery)
Run Code Online (Sandbox Code Playgroud)

右侧是带括号的子查询,该查询必须恰好返回一列。评估左侧表达式并将其与子查询结果的每一行进行比较。IN如果找到相等的子查询行,则结果为“ true”。如果找不到相等的行,则结果为“ false”(包括子查询不返回任何行的情况)。

或带有文字列表

9.23.1。在

expression IN (value [, ...])
Run Code Online (Sandbox Code Playgroud)

右侧是带括号的标量表达式列表。如果左侧表达式的结果等于任何右侧表达式,则结果为“ true”。这是的简写

expression = value1
OR
expression = value2
OR
...
Run Code Online (Sandbox Code Playgroud)

因此a IN b或多或少意味着:

该值a等于列表中的任何值b(可以是产生单个元素行或文字列表的查询)。

当然,您可以这样说:

array[1] in (select some_array from ...)
array[1] in (array[1], array[2,3])
Run Code Online (Sandbox Code Playgroud)

但是在这种情况下,数组仍被视为单个值(恰好具有某些内部结构)。


如果要检查数组是否包含值列表中的任何一个,则@>不是您想要的。考虑一下:

array[1,2] @> array[2,4]
Run Code Online (Sandbox Code Playgroud)

4不在,array[1,2]因此array[2,4]不是的子集array[1,2]

如果要检查某人是否同时具有这两个角色,请:

roles @> array['as_champion', 'whatever']
Run Code Online (Sandbox Code Playgroud)

是合适的表情,但如果你想检查是否roles任何这些值,那么你想要的重叠运算符(&&):

roles && array['as_champion', 'whatever']
Run Code Online (Sandbox Code Playgroud)

请注意,我到处都在对数组使用“数组构造函数”语法,这是因为使用工具(例如ActiveRecord)在替换占位符时知道将数组扩展为以逗号分隔的列表更为方便。不能完全理解SQL数组。

考虑到所有这些,我们可以说诸如此类:

Membership.where('roles @> array[?]', %w[as_champion whatever])
Membership.where('roles @> array[:roles]', :roles => some_ruby_array_of_strings)
Run Code Online (Sandbox Code Playgroud)

一切都会按预期进行。您仍在使用少量SQL代码段(因为ActiveRecord对SQL数组或表示@>操作符的方式没有完全的了解),但至少您不必担心引用问题。您可能可以通过AREL手动添加@>支持,但是我发现AREL很快变成了除了最琐碎的用途以外所有其他人都无法理解且难以理解的混乱。