Oui, le opérateur de chevauchement &&
pourrait utiliser un index GIN sur les tableaux
. Très utile pour les requêtes celle-ci pour trouver des lignes avec une personne donnée (1
) parmi un panel d'acteurs :
SELECT * FROM eg_assoc WHERE actors && '{1}'::int[]
Cependant , la logique de votre requête est inverse, recherchant toutes les personnes listées dans les tableaux dans eg_assoc
. Un indice GIN est non aide ici. Nous avons juste besoin de l'index btree du PK person.id
.
Requêtes appropriées
Notions de base :
Les requêtes suivantes préservent les tableaux d'origine exactement tels qu'ils sont donnés , y compris les éventuels éléments en double et l'ordre d'origine des éléments. Fonctionne pour les tableaux unidimensionnels . Les dimensions supplémentaires sont pliées en une seule dimension. Il est plus complexe de conserver plusieurs dimensions (mais tout à fait possible) :
WITH ORDINALITY
dans Postgres 9.4 ou version ultérieure
SELECT aid, actors
, ARRAY(SELECT name
FROM unnest(e.actors) WITH ORDINALITY a(id, i)
JOIN eg_person p USING (id)
ORDER BY a.i) AS act_names
, benefactors
, ARRAY(SELECT name
FROM unnest(e.benefactors) WITH ORDINALITY b(id, i)
JOIN eg_person USING (id)
ORDER BY b.i) AS ben_names
FROM eg_assoc e;
LATERAL
requêtes
Pour PostgreSQL 9.3+ .
SELECT e.aid, e.actors, a.act_names, e.benefactors, b.ben_names
FROM eg_assoc e
, LATERAL (
SELECT ARRAY( SELECT name
FROM generate_subscripts(e.actors, 1) i
JOIN eg_person p ON p.id = e.actors[i]
ORDER BY i)
) a(act_names)
, LATERAL (
SELECT ARRAY( SELECT name
FROM generate_subscripts(e.benefactors, 1) i
JOIN eg_person p ON p.id = e.benefactors[i]
ORDER BY i)
) b(ben_names);
db<>violon ici
avec quelques variantes.
Ancien sqlfiddle
Détail subtil :si une personne n'est pas retrouvée, elle est simplement abandonnée. Ces deux requêtes génèrent un tableau vide ('{}'
) si aucune personne n'est trouvée pour l'ensemble du tableau. D'autres styles de requête renverraient NULL
. J'ai ajouté des variantes au violon.
Sous-requêtes corrélées
Pour Postgres 8.4+ (où generate_subsrcipts()
a été introduit) :
SELECT aid, actors
, ARRAY(SELECT name
FROM generate_subscripts(e.actors, 1) i
JOIN eg_person p ON p.id = e.actors[i]
ORDER BY i) AS act_names
, benefactors
, ARRAY(SELECT name
FROM generate_subscripts(e.benefactors, 1) i
JOIN eg_person p ON p.id = e.benefactors[i]
ORDER BY i) AS ben_names
FROM eg_assoc e;
Peut toujours fonctionner mieux, même dans Postgres 9.3.
Le ARRAY
constructeur
est plus rapide que array_agg()
. Voir :
Votre requête a échoué
La requête fournie par @a_horse semble pour faire le travail, mais il n'est pas fiable, trompeur, potentiellement incorrect et inutilement coûteux.
-
Jointure croisée proxy en raison de deux jointures non liées. Un anti-modèle sournois. Voir :
Corrigé superficiellement avec
DISTINCT
dansarray_agg()
pour éliminer les doublons générés, mais c'est vraiment mettre du rouge à lèvres sur un cochon. Cela élimine également les doublons dans l'original car il est impossible de faire la différence à ce stade - ce qui est potentiellement incorrect. -
L'expression
a_person.id = any(eg_assoc.actors)
fonctionne , mais élimine les doublons du résultat (se produit deux fois dans cette requête), ce qui est faux sauf indication contraire. -
L'ordre d'origine des éléments du tableau n'est pas conservé . C'est délicat en général. Mais c'est aggravé dans cette requête, car acteurs et bienfaiteurs se multiplient et se distinguent à nouveau, ce qui garantit ordre arbitraire.
-
Aucun alias de colonne dans le
SELECT
externe entraîner des noms de colonnes en double, ce qui fait échouer certains clients (ne fonctionnant pas dans le violon sans alias). -
min(actors)
etmin(benefactors)
sont inutiles. Normalement, on ajouterait simplement les colonnes àGROUP BY
au lieu de les fausser en les agrégeant. Maiseg_assoc.aid
est de toute façon la colonne PK (couvrant toute la table dansGROUP BY
), donc ce n'est même pas nécessaire. Justeactors, benefactors
.
L'agrégation de l'ensemble du résultat est une perte de temps et d'efforts pour commencer. Utilisez une requête plus intelligente qui ne multiplie pas les lignes de base, vous n'avez alors pas à les agréger.