簡體   English   中英

查詢Postgres數組列類型

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM