PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Demande de requête de transposition de tableau croisé

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 :

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 :

Notez également que le prochain Postgres 9.5 (actuellement bêta) introduit un Clause SQL pour ROLLUP .
Connexe :