web-dev-qa-db-fra.com

Postgres - Transposer des lignes en colonnes

J'ai le tableau suivant, qui donne plusieurs adresses électroniques pour chaque utilisateur.

enter image description here

J'ai besoin d'aplanir ceci aux colonnes d'une requête utilisateur. Pour me donner les "plus récentes" 3 adresses email basées sur la date de création.

user.name | user.id | email1          | email2           | email3**

Mary      | 123     | [email protected]  | [email protected] | [email protected]

Joe       | 345     | [email protected]   | [NULL]           | [NULL]
33
dacology

Utilisez crosstab() du module tablefunc .

SELECT * FROM crosstab(
   $$SELECT user_id, user_name, rn, email_address
     FROM  (
        SELECT u.user_id, u.user_name, e.email_address
             , row_number() OVER (PARTITION BY u.user_id
                            ORDER BY e.creation_date DESC NULLS LAST) AS rn
        FROM   usr u
        LEFT   JOIN email_tbl e USING (user_id)
        ) sub
     WHERE  rn < 4
     ORDER  BY user_id
   $$
  , 'VALUES (1),(2),(3)'
   ) AS t (user_id int, user_name text, email1 text, email2 text, email3 text);

J'ai utilisé la cotation en dollars pour le premier paramètre, qui n'a pas de signification particulière. C'est pratique si vous devez échapper des guillemets simples dans la chaîne de requête, ce qui est un cas courant:

Explication détaillée et instructions ici:

Et en particulier, pour les "colonnes supplémentaires":

Les difficultés spéciales sont les suivantes:

  • Le manque de noms de clés.
    -> Nous substituons avec row_number() dans une sous-requête.

  • Le nombre variable d'emails.
    -> Nous limitons à max. de trois à l'extérieur SELECT
    et utilisez crosstab() avec deux paramètres, fournissant une liste des clés possibles.

Faites attention à NULLS LAST Dans le ORDER BY .

44
Erwin Brandstetter

Si quelqu'un d'autre trouve cette question et a besoin d'une solution dynamique pour laquelle vous avez un nombre indéfini de colonnes à transposer et pas exactement 3, vous pouvez trouver une solution Nice ici: https://github.com/ jumpstarter-io/colpivot

12
Hannes Landeholm

le code ci-dessus m'a vraiment aidé. Maintenant, j'essaie d'ajouter plus de champs au tableau croisé dynamique.

    SELECT * INTO temp_pivot_table FROM crosstab(
    $$SELECT lead_id, magazine_id, days_between_mailers, rn
    FROM  (
    SELECT u.lead_id, u.magazine_id, u.days_between_mailers
         , row_number() OVER (PARTITION BY u.lead_id
                        ORDER BY u.id ASC NULLS LAST) AS rn
    FROM   temp_mailer_stats u
    ) sub
    WHERE  rn <= 3
    ORDER  BY lead_id
   $$

  , 'VALUES (1),(2),(3),(4),(5),(6)'
  ) AS t (lead_id int, magazine1 text, magazine2 text, magazine3 text, 
   days_between1 integer, days_between2 integer, days_between3 integer);

Bien sûr, je peux créer des tables séparées, puis les associer, mais si je pouvais enregistrer une étape, ce serait idéal.

Merci d'avance pour l'aide.

0
ja11946