Das funktioniert:
SELECT *
FROM element
WHERE (pk1, pk2, pk3) IN (SELECT (unnest(elements)).*
FROM collection
WHERE id = 1);
Oder ausführlicher, aber bevorzugt :
SELECT *
FROM element
WHERE (pk1, pk2, pk3) IN (SELECT (e).*
FROM collection c, unnest(c.elements) e
WHERE c.id = 1);
Robuster und vermeidet die Auswertung von unnest()
mehrmals. Siehe:
Das geht auch:
SELECT *
FROM element
WHERE ROW((pk1, pk2, pk3)) IN (SELECT unnest(elements)
FROM collection
WHERE id = 1);
Der Kern des Problems ist, dass IN
Unterabfrage ausführen kennt zwei getrennte Formen. Zitieren von dem Handbuch:
Ihre fehlgeschlagene Abfrage löst sich in die zweite Form auf, während Sie (verständlicherweise) die erste erwarten. Aber die zweite Form tut dies:
Meine erste und zweite Anfrage damit es funktioniert, indem Sie den Zeilentyp zerlegen
rechts vom Betreiber. Postgres hat also drei bigint
Werte links und rechts und ist zufrieden.
Meine dritte Abfrage funktioniert, indem der Zeilentyp links in einem anderen Zeilenkonstruktor . Postgres zerlegt nur die erste Ebene und endet mit einem einzigen zusammengesetzten Typ – passend zum einzelnen zusammengesetzten Typ rechts.
Beachten Sie, dass das Schlüsselwort ROW
ist für das einzelne Feld erforderlich, das wir umschließen. Das Handbuch:
Ihre Arbeitsabfrage ist etwas anders, da es eine Liste bereitstellt von Werten rechts anstelle einer Unterabfrage (einstellen ). Das ist eine andere Implementierung, die einen anderen Codepfad nimmt. Es bekommt sogar ein separates Kapitel im Handbuch . Diese Variante hat keine spezielle Behandlung für einen ROW-Konstruktor auf der linken Seite. Es funktioniert also wie erwartet (von Ihnen).
Äquivalentere (funktionierende) Syntaxvarianten mit = ANY
:
SELECT * FROM element
WHERE (pk1, pk2, pk3) = ANY ('{"(1,2,3)","(2,3,4)"}'::element_pk_t[]);
SELECT * FROM element
WHERE (pk1, pk2, pk3) = ANY (ARRAY[(1,2,3)::element_pk_t,(2,3,4)::element_pk_t]);
SELECT * FROM element
WHERE (pk1, pk2, pk3) = ANY (ARRAY[(1,2,3),(2,3,4)]::element[]);
Auch gültig mit (pk1, pk2, pk3)::element_pk_t
oder ROW(pk1, pk2, pk3)::element_pk_t
Siehe:
Da Ihre Quelle ein Array ist , Daniels zweite Abfrage mit (e.pk1, e.pk2, e.pk3) = ANY(c.elements)
bietet sich natürlich an.
Aber für eine Wette auf die schnellste Abfrage , ich setze auf meine zweite Variante, weil ich mir erwarte, dass sie den PK-Index optimal nutzt.
Nur als Proof-of-Concept. Wie a_horse kommentierte:Ein normalisiertes DB-Design wird wahrscheinlich am besten skalieren.