0

TL;DR Ich frage mich, was die Vor- und Nachteile sind (oder ob sie sogar gleichwertig sind) zwischen @> {as_champion, whatever} und IN ('as_champion', 'whatever') ist. Details unten:Abfrage gegen eine Postgres Array Spalte Typ

Ich arbeite mit Rails und mit Postgres Array-Spalte Typ, sondern mit Raw SQL für meine Abfrage, da die Rails Finder-Methoden nicht gut damit spielen. Ich fand einen Weg, der funktioniert, aber ich frage mich, was die bevorzugte Methode ist:

Die roles Spalte auf der Memberships Tabelle ist meine Array-Spalte. Es wurde als so über Schienen hinzugefügt:

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

Wenn ich die Tabelle untersuchen, es zeigt die Art, wie:. text[] (nicht sicher, ob das wirklich ist, wie Postgres einen Array Spalt steht oder wenn die Rails Spielereien

Zur Abfrage dagegen ich so etwas wie:

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

Der Operator '@>' bedeutet "enthält": Es ist wahr, wenn das linke Array alle Elemente im rechten Array enthält. Der Operator "IN" wird mit grundlegenden Datentypen verwendet, nicht mit Arrays. – Andomar

+0

@Andomar nach grundlegenden Datentypen, meinst du "IN" wird nur verwendet, um zu überprüfen, ob ein Wert gleich einer einzelnen Zeichenkette oder Ganzzahl oder etwas in der bereitgestellten Liste ist? Wo als '@>' muss sie alle enthalten? – mackshkatz

Antwort

2

Vom feinen Array Operators manual:

Betreiber: @>
Beschreibung: enthält
Beispiel: ARRAY[1,4,3] @> ARRAY[3,1]
Ergebnis: t (AKA wahr)

So @> behandelt seine Operanden-Arrays als Sätze und prüft, ob die rechte Seite eine Teilmenge der linken Seite .

IN ist ein wenig anders und wird verwendet, mit subqueries:

9.22.2. IN

expression IN (subquery) 

Die rechte Seite ist eine geklammerte Unterabfrage, die genau eine Spalte zurückkehren. Der linke Ausdruck wird ausgewertet und mit jeder Zeile des Unterabfrageergebnisses verglichen. Das Ergebnis von IN ist "wahr", wenn eine Zeile gleicher Unterabfrage gefunden wird. Das Ergebnis ist "false", wenn keine gleiche Zeile gefunden wird (einschließlich des Falls, in dem die Unterabfrage keine Zeilen zurückgibt).

oder mit literal lists:

9.23.1. IN

expression IN (value [, ...]) 

Die rechte Seite ist eine geklammerten Liste von skalaren Ausdrücken. Das Ergebnis ist "wahr", wenn das Ergebnis des linken Ausdrucks einem der rechten Ausdrücke entspricht.Dies ist eine Kurzschreibweise für

expression = value1 
OR 
expression = value2 
OR 
... 

So a IN b mehr oder weniger Mittel:

Ist der Wert a gleich einem der Werte in der Liste b (die eine Abfrage produzieren kann Single Elementzeilen oder eine Literalliste).

Natürlich können Sie sagen Dinge wie:

array[1] in (select some_array from ...) 
array[1] in (array[1], array[2,3]) 

aber die Anordnungen in diesen Fällen sind immer noch wie einzelne Werte behandelt (das nur passieren einige interne Struktur haben).


Wenn Sie überprüfen wollen, ob ein Array beliebige aus einer Liste von Werten enthält dann @> ist nicht das, was Sie wollen. Bedenken Sie:

array[1,2] @> array[2,4] 

4 ist nicht in array[1,2] so array[2,4] nicht eine Teilmenge von array[1,2] ist.

Wenn Sie überprüfen wollen, ob jemand beide Rollen hat dann:

roles @> array['as_champion', 'whatever'] 

ist der richtige Ausdruck, aber wenn Sie überprüfen möchten, ob rolesist jede dieser Werte dann wollen Sie die Überlappungen Operator (&&):

roles && array['as_champion', 'whatever'] 

Bitte beachte, dass ich mit dem „Array-Konstruktor“ Syntax für die überall Arrays, das ist, weil es ist viel bequemer für die Arbeit mit einem Tool (wie ActiveRecord), das ein Array in eine durch Kommas getrennte Liste erweitern kann, wenn er einen Platzhalter ersetzt, aber SQL-Arrays nicht vollständig versteht.

alles gegeben, können wir sagen Dinge wie:

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

und alles wird wie erwartet. Sie arbeiten immer noch mit kleinen SQL-Snippets (da ActiveRecord SQL-Arrays nicht vollständig versteht oder den Operator @> darstellt), aber Sie müssen sich zumindest keine Sorgen über Probleme machen. Sie könnten wahrscheinlich durch AREL gehen, um manuell @> Unterstützung hinzuzufügen, aber ich finde, dass AREL schnell in eine unverständliche und unlesbare Verwirrung für alle außer die trivialsten Verwendungen gerät.

+1

Erstaunliche Antwort! Für Ihre Beschreibung des @> - Operators sagen Sie, dass er überprüft, ob die linke Seite eine Teilmenge der rechten Seite ist. Ich denke, Sie haben * Supermenge * gemeint. (Ich versuchte, es zu bearbeiten, aber die Änderung war zu klein, um – mackshkatz

+1

@mackshkatz einzureichen. Richtig meinte ich "rechte Seite ist eine Teilmenge der linken Seite" (oder äquivalent, "linke Seite ist eine Obermenge der rechten Seite"). Danke für das Zeigen das heraus. –

Verwandte Themen