La difficulté particulière est que vos données ne sont pas prêtes pour la tabulation croisée. Vous avez besoin de données sous la forme row_name , catégorie , valeur . Vous pouvez l'obtenir avec un UNION
requête :
SELECT 'metric1' AS metric, country_code, metric1 FROM tbl1
UNION ALL
SELECT 'metric2' AS metric, country_code, metric2 FROM tbl1
UNION ALL
SELECT 'metric3' AS metric, country_code, metric3 FROM tbl1
ORDER BY 1, 2 DESC;
Mais un LATERAL
intelligent la requête ne nécessite qu'un seul parcours de table et sera plus rapide :
SELECT x.metric, t.country_code, x.val
FROM tbl1 t
, LATERAL (VALUES
('metric1', metric1)
, ('metric2', metric2)
, ('metric3', metric3)
) x(metric, val)
ORDER BY 1, 2 DESC;
Connexe :
- Quelle est la différence entre LATERAL et une sous-requête dans PostgreSQL ?
- SELECT DISTINCT sur plusieurs colonnes
Utilisation de la forme simple de crosstab()
avec 1 paramètre avec cette requête en entrée :
SELECT * FROM crosstab(
$$SELECT x.metric, t.country_code, x.val
FROM tbl1 t
, LATERAL (VALUES
('metric1', metric1)
, ('metric2', metric2)
, ('metric3', metric3)
) x(metric, val)
ORDER BY 1, 2 DESC$$
)
AS ct (metric text, us int, uk int, fr int);
Listez les noms de pays par ordre alphabétique décroissant (comme dans votre démo). Cela suppose également que toutes les mesures sont définies NOT NULL
.
Si l'un ou les deux ne sont pas le cas, utilisez plutôt le formulaire à 2 paramètres :
Ajouter "cumul"
C'est à dire. totaux par métrique :
SELECT * FROM crosstab(
$$SELECT x.metric, t.country_code, x.val
FROM (
TABLE tbl1
UNION ALL
SELECT 'zzz_total', sum(metric1)::int, sum(metric2)::int, sum(metric3)::int -- etc.
FROM tbl1
) t
, LATERAL (VALUES
('metric1', metric1)
, ('metric2', metric2)
, ('metric3', metric3)
) x(metric, val)
ORDER BY 1, 2 DESC$$
)
AS ct (metric text, total int, us int, uk int, fr int);
'zzz_total'
est une étiquette arbitraire, qui doit être triée en dernier par ordre alphabétique (ou vous avez besoin de la forme à 2 paramètres de crosstab()
).
Si vous avez beaucoup de colonnes de métriques, vous souhaiterez peut-être créer la chaîne de requête de manière dynamique. Connexe :
- Comment effectuer la même agrégation sur chaque colonne, sans lister les colonnes ?
- Exécution dynamique de requêtes en PL/ pgSQL
Notez également que le prochain Postgres 9.5 (actuellement bêta) introduit un Clause SQL pour ROLLUP
.
Connexe :