1

J'ai une configuration assez commun pour une base de données d'adresse: une person est liée à un company avec une table de jointure, le company peut avoir un address et ainsi de suite.sous-requête qui correspond à la colonne avec plusieurs plages définies dans le tableau

Tous assez normalisé et facile à utiliser. Mais pour la performance de recherche, je crée une vue matérialisée, plutôt dénormalisée. J'ai seulement besoin d'un ensemble très limité d'informations et de requêtes rapides. La plupart de tout ce qui est habituellement fait via une table de jointure est maintenant dans un tableau. Selon la requête, je peux le rechercher directement ou le rejoindre via unnest.

En complément à ma colonne zipcodes (varchar[]), je voudrais ajouter une colonne states qui a le (fedaral allemand) des Etats déjà précalculées, de sorte que je n'ai pas de transformer une requête pour inclure toutes sortes des comparaisons de distance.

Ma date de mise en correspondance est dans un tableau comme celui-ci:

CREATE TABLE zip2state (
    state TEXT NOT NULL, 
    range_start CHARACTER VARYING(5) NOT NULL, 
    range_end CHARACTER VARYING(5) NOT NULL 
) 

Chaque état a plusieurs gammes et gammes peuvent se chevaucher (un code peut être pour deux états différents). Certaines plages ont range_start = range_end.

Maintenant, je suis un peu à la fin de l'esprit sur la façon d'intégrer cela dans une vue matérialisée à la fois. Normalement, je serais tenté de le faire de manière itérative (via un trigger ou au niveau de l'application). Ou, comme nous venons de parler 5 chiffres, je pourrais créer un grand zip de mappage de table pour indiquer directement au lieu de le faire via une plage (mon favori actuel, mais quelque chose d'assez laid qu'il m'a incité à se demander s'il y a une meilleure façon)

Toute façon de le faire dans SQL, avec une table comme celle-ci (ou quelque chose de similaire)? Je suis à postgres 9.3, toutes les fonctions autorisées ...

Par souci d'exhaustivité, voici la sous-requête pour les codes postaux:

(select array_agg(distinct address.zipcode) 
     from affiliation 
     join company 
     on affiliation.ins_id = company.id 
     join address 
     on address.com_id = company.id 
    where affiliation.per_id = person.id) AS zipcodes, 

Répondre

1

Je propose une LATERAL rejoindre au lieu de la sous-requête corrélée pour calculer commodément les deux colonnes à la fois. Pourrait ressembler à ceci:

SELECT p.*, z.* 
FROM person p 
LEFT JOIN LATERAL (
    SELECT array_agg(DISTINCT d.zipcode) AS zipcodes 
     , array_agg(DISTINCT z.state) AS states 
    FROM affiliation a 
    -- JOIN company  c ON a.ins_id = c.id -- suspect you don't need this 
    JOIN address  d ON d.com_id = a.ins_id -- c.id 
    LEFT JOIN zip2state z ON d.zipcode BETWEEN z.range_start AND z.range_end 
    WHERE a.per_id = p.id 
    ) z ON true; 

Si l'intégrité référentielle est garanti, vous n'avez pas besoin de se joindre à la table company du tout. J'ai pris le raccourci. Sachez que varchar ou text se comporte différemment que prévu pour les nombres. Par exemple: '333' > '0999'. Si tous les codes postaux ont 5 chiffres vous allez bien.

connexes:

+0

Impressionnant, non seulement avez-vous répondu à ma question, mais vous avez également permis d'optimiser la requête et m'a fait prendre conscience d'une nouvelle fonctionnalité de SQL que je peux exploiter A l'avenir. Geeze, un simple "LEFT JOIN" pour tout avoir dans les gammes, j'y pensais vraiment trop cette fois ... – mhd