web-dev-qa-db-fra.com

Requête LIKE PostgreSQL sur le champ ARRAY

Existe-t-il un moyen d'avoir une requête Postgres LIKE sur un champ ARRAY?

Actuellement, je veux quelque chose comme ça:

SELECT * FROM list WHERE lower(array_field) LIKE '1234%'

Actuellement plus bas n'est pas nécessaire autant. Cependant, il devrait trouver UN champ correspondant à l'intérieur du RÉSEAU. Est-ce que c'est possible?

Actuellement, j'utilise une vue matérialisée pour générer la table "liste" avec une JOIN et une ARRAY_AGG(), car je JOIGNE une table où plus de valeurs pourraient être sur la bonne table. Ce qui dupliquerait les champs de la table de gauche, ce qui n'est pas ce que je veux.

Modifier c'est ainsi que je crée la vue (vraiment lente et moche):

CREATE MATERIALIZED VIEW article_list_new AS
SELECT a.id, 
       a.oa_nr, 
       a.date_deleted, 
       a.lock, 
       a.sds_nr, 
       a.kd_art_nr, 
       a.kd_art_index, 
       a.kd_art_extend, 
       a.surface, 
       a.execution, 
       a.surface_area, 
       a.cu_thickness, 
       a.endintensity, 
       a.drilling, 
       array_agg(o.id::text) AS offer_list 
FROM article_list a LEFT JOIN task_offer o ON o.article = a.oa_nr 
GROUP BY .....;  

Je dois également renvoyer les ID de la table task_offer.

7
Christian Schmitt

Vous pouvez utiliser unnest() comme @dezso déjà mentionné, par exemple avec une jointure LATERAL (Postgres 9.3+)

SELECT l.*
FROM   list l, unnest(array_field) a  -- implicit lateral
WHERE  lower(a) LIKE '1234%';

Vous n'avez besoin de rien de tout cela pour le cas présenté. Pas de vue matérialisée du tout. Cette requête sur les tables sous-jacentes est plus rapide, car elle peut utiliser un index:

SELECT *  -- or selected columns
FROM   article_list a
JOIN   LATERAL  (                      -- only matching IDs
   SELECT array_agg(id) AS offer_list
   FROM   task_offer
   WHERE  article = a.oa_nr            -- LATERAL reference  
   AND    id::text ILIKE '1234%'       -- or just LIKE
   ) o ON offer_list IS NOT NULL;

offer_list est un tableau du type de données d'origine dans mon résultat et contient uniquement les ID correspondants.

Renvoie une seule ligne de article_list avec un tableau d'ID correspondants dans task_offer. Ajouter un text_pattern_ops index (pour les correspondances ancrées à gauche) pour obtenir les meilleures performances de lecture:

CREATE INDEX task_offer_foo_idx ON task_offer (article, (id::text) text_pattern_ops);

Ou un index de trigramme pour les correspondances d'infixe (non ancré à gauche):

Ou peut-être une simple jointure pour des modèles sélectifs:

SELECT a.*, o.offer_list -- or selected columns
FROM   article_list a
JOIN   (                          -- only matching IDs
   SELECT article, array_agg(id) AS offer_list
   FROM   task_offer
   WHERE  id::text ILIKE '1234%'  -- or just LIKE
   GROUP  BY 1
   ) o ON o.article = a.oa_nr;

Besoin d'un index sur article_list, aussi. (Ce que vous avez probablement - aucune information dans la question.) Comme:

CREATE INDEX article_list_oa_nr_idx ON article_list (oa_nr);
9
Erwin Brandstetter

Avez-vous pensé à extension parray_gin , également situé ici ?

Je ne l'ai pas encore utilisé en production, mais d'après ce que j'en ai vu, il fait ce que vous voulez contre le tableau. Vous pouvez créer l'index approprié sur la vue matérialisée.

Cependant, je ne ferais cela que si vous voulez avoir une vue matérialisée de toute façon. Sinon, je pense que la réponse de @ ErwinBrandstetter est meilleure que de créer une vue matérialisée uniquement pour contenir l'index.

4
jjanes