【问题标题】:Query against a Postgres array column type针对 Postgres 数组列类型进行查询
【发布时间】:2017-05-12 17:03:33
【问题描述】:

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

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

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

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

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

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

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

【问题讨论】:

  • @> 运算符表示“包含”:如果左侧数组包含右侧数组中的所有元素,则为 true。 IN 运算符用于基本数据类型,而不是数组。
  • @Andomar 按基本数据类型,您的意思是IN 仅用于检查值是否等于提供的列表中的单个字符串或整数或其他内容? @> 需要在哪里包含所有这些?

标签: ruby-on-rails postgresql ruby-on-rails-4 rails-activerecord array-column


【解决方案1】:

来自罚款Array Operators manual

操作员:@>
说明:包含
示例:ARRAY[1,4,3] @> ARRAY[3,1]
结果:t (AKA true)

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

IN有点不同,和subqueries一起使用:

9.22.2。在

expression IN (subquery)

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

literal lists:

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 不在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 sn-ps(因为 ActiveRecord 对 SQL 数组或任何表示 @> 运算符的方式没有完全理解)但至少您不必担心引用问题。您可能可以通过 AREL 手动添加 @> 支持,但我发现 AREL 很快就会变成一个难以理解和难以理解的混乱,除了最琐碎的用途。

【讨论】:

  • 惊人的答案!对于您对@> 运算符的描述,您说它检查左侧是否是右侧的子集,我认为您的意思是superset。 (我试图编辑它,但更改太小无法提交
  • @mackshkatz 对,我的意思是“右侧是左侧的子集”(或等效地,“左侧是右侧的超集”)。感谢您指出这一点。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-26
  • 1970-01-01
  • 2012-08-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多