Cela fonctionne :
SELECT *
FROM element
WHERE (pk1, pk2, pk3) IN (SELECT (unnest(elements)).*
FROM collection
WHERE id = 1);
Ou plus verbeux, mais préférable :
SELECT *
FROM element
WHERE (pk1, pk2, pk3) IN (SELECT (e).*
FROM collection c, unnest(c.elements) e
WHERE c.id = 1);
Plus robuste et évite d'évaluer unnest()
plusieurs fois. Voir :
Cela fonctionne aussi :
SELECT *
FROM element
WHERE ROW((pk1, pk2, pk3)) IN (SELECT unnest(elements)
FROM collection
WHERE id = 1);
Le cœur du problème est que IN
prendre une sous-requête connaît deux formes distinctes. Citant le manuel :
Votre requête ayant échoué se résout à la deuxième forme, alors que vous vous attendez (naturellement) à la première. Mais le deuxième formulaire fait ceci :
Ma première et deuxième requête faites-le fonctionner en décomposant le type de ligne
à droite de l'opérateur. Donc Postgres a trois bigint
valeurs à gauche et à droite et est satisfait.
Ma troisième requête le fait fonctionner en imbriquant le type de ligne à gauche dans un autre constructeur de lignes . Postgres ne décompose que le premier niveau et se retrouve avec un seul type composite - correspondant au type composite unique à droite.
Notez que le mot-clé ROW
est requis pour le seul champ que nous enveloppons. Le manuel :
Votre requête de travail est subtilement différent car il fournit une liste de valeurs à droite au lieu d'une sous-requête (définir ). C'est une implémentation différente prenant un chemin de code différent. Il obtient même un chapitre séparé dans le manuel . Cette variante n'a pas de traitement spécial pour un constructeur ROW à gauche. Cela fonctionne donc comme prévu (par vous).
Plus de variantes de syntaxe équivalentes (fonctionnelles) avec = 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[]);
Valable aussi avec (pk1, pk2, pk3)::element_pk_t
ou ROW(pk1, pk2, pk3)::element_pk_t
Voir :
Puisque votre source est un tableau , deuxième requête de Daniel avec (e.pk1, e.pk2, e.pk3) = ANY(c.elements)
se prête naturellement.
Mais pour un pari sur la requête la plus rapide , mon pari est sur ma deuxième variante, car je m'attends à ce qu'elle utilise l'indice PK de manière optimale.
Tout comme une preuve de concept. Comme a_horse l'a commenté :une conception de base de données normalisée sera probablement la meilleure mise à l'échelle.