J'ai le tableau suivant, qui donne plusieurs adresses électroniques pour chaque utilisateur.
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]
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
.
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
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.