[英]Query against a Postgres array column type
TL;DR
我想知道@> {as_champion, whatever}
和使用IN ('as_champion', 'whatever')
之间的优缺点(或者是否等同)。 详情如下:
我正在使用Rails并使用Postgres的数组列类型,但是由于Rails finder方法不能很好地使用它,因此不得不对查询使用原始sql。 我找到了一种可行的方法,但想知道首选的方法是:
Memberships
表上的roles
列是我的数组列。 它是通过rails这样添加的:
add_column :memberships, :roles, :text, array: true
当我检查表时,它显示的类型为: text[]
(不确定这是否是Postgres真正表示数组列的方式,还是那是Rails shenanigans。
要查询它,我要做类似的事情:
Membership.where("roles @> ?", '{as_champion, whatever}')
从优良的Array Operators手册中 :
操作员:
@>
说明:包含
示例:ARRAY[1,4,3] @> ARRAY[3,1]
结果:t
(又称是)
因此@>
将其操作数数组视为集合,并检查右侧是否是左侧的子集。
IN
有点不同,并且与子查询一起使用 :
9.22.2。 在
expression IN (subquery)
右侧是带括号的子查询,该查询必须恰好返回一列。 评估左侧表达式并将其与子查询结果的每一行进行比较。 如果找到相等的子查询行,则
IN
的结果为“ true”。 如果找不到相等的行,则结果为“ false”(包括子查询不返回任何行的情况)。
或带有文字列表 :
9.23.1。 在
expression IN (value [, ...])
右侧是带括号的标量表达式列表。 如果左侧表达式的结果等于任何右侧表达式,则结果为“ true”。 这是的简写
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
不在array[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很快演变为除了最琐碎的用途之外所有其他用途的令人费解和难以理解的混乱。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.