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

Pivot sur plusieurs colonnes à l'aide de Tablefunc

Le problème avec votre requête est que b et c partager le même horodatage 2012-01-02 00:00:00 , et vous avez le timestamp colonne timeof en premier dans votre requête, donc - même si vous avez ajouté une emphase en gras - b et c sont juste des colonnes supplémentaires qui tombent dans le même groupe 2012-01-02 00:00:00 . Seul le premier (b ) est renvoyé depuis (citant le manuel) :

Le row_name colonne doit être la première. La category et value les colonnes doivent être les deux dernières colonnes, dans cet ordre. Toutes les colonnes entre row_name et category sont traités comme "extra". Les colonnes "supplémentaires" doivent être identiques pour toutes les lignes avec le même row_name valeur.

Gras gras le mien.
Il suffit d'inverser l'ordre des deux premières colonnes pour faire de l'entity le nom de la ligne et cela fonctionne comme vous le souhaitez :

SELECT * FROM crosstab(
      'SELECT entity, timeof, status, ct
       FROM   t4
       ORDER  BY 1'
      ,'VALUES (1), (0)')
 AS ct (
    "Attribute" character
   ,"Section" timestamp
   ,"status_1" int
   ,"status_0" int);

entity doit être unique, bien sûr.

Réitérez

  • row_name premier
  • (facultatif) extra colonnes suivant
  • category (tel que défini par le second paramètre) et value dernier .

Les colonnes supplémentaires sont remplies à partir de la première ligne de chaque row_name cloison. Les valeurs des autres lignes sont ignorées, il n'y a qu'une seule colonne par row_name remplir. En règle générale, ceux-ci seraient les mêmes pour chaque ligne d'un row_name , mais c'est à vous de décider.

Pour la configuration différente dans votre réponse :

SELECT localt, entity
     , msrmnt01, msrmnt02, msrmnt03, msrmnt04, msrmnt05  -- , more?
FROM   crosstab(
        'SELECT dense_rank() OVER (ORDER BY localt, entity)::int AS row_name
              , localt, entity -- additional columns
              , msrmnt, val
         FROM   test
         -- WHERE  ???   -- instead of LIMIT at the end
         ORDER  BY localt, entity, msrmnt
         -- LIMIT ???'   -- instead of LIMIT at the end
     , $$SELECT generate_series(1,5)$$)  -- more?
     AS ct (row_name int, localt timestamp, entity int
          , msrmnt01 float8, msrmnt02 float8, msrmnt03 float8, msrmnt04 float8, msrmnt05 float8 -- , more?
            )
LIMIT 1000  -- ??!!

Pas étonnant que les requêtes de votre test fonctionnent terriblement. Votre configuration de test comporte 14 millions de lignes et vous traitez toutes d'eux avant de jeter la plupart avec LIMIT 1000 . Pour un ensemble de résultats réduit, ajoutez des conditions WHERE ou une LIMITE à la requête source !

De plus, la baie avec laquelle vous travaillez est inutilement chère. Je génère un nom de ligne de substitution avec dense_rank() à la place.

db<>violon ici - avec une configuration de test plus simple et moins de lignes.