PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Pivotieren Sie mehrere Spalten mit Tablefunc

Das Problem mit Ihrer Abfrage ist, dass b und c denselben Zeitstempel haben 2012-01-02 00:00:00 , und Sie haben den timestamp Spalte timeof zuerst in Ihrer Abfrage, also - obwohl Sie fett hervorgehoben haben - b und c sind nur zusätzliche Spalten, die in dieselbe Gruppe 2012-01-02 00:00:00 fallen . Nur der erste (b ) wird zurückgegeben seit (unter Angabe des Handbuchs):

Der row_name Spalte muss an erster Stelle stehen. Die category und value Spalten müssen die letzten beiden Spalten in dieser Reihenfolge sein. Alle Spalten zwischen row_name und category werden als „zusätzlich“ behandelt. Die "zusätzlichen" Spalten sind voraussichtlich gleich für alle Zeilen mit demselben row_name Wert.

Fettdruck von mir.
Kehren Sie einfach die Reihenfolge der ersten beiden Spalten um, um entity zu erstellen den Zeilennamen und es funktioniert wie gewünscht:

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 muss natürlich eindeutig sein.

Wiederholen

  • row_name zuerst
  • (optional) extra Spalten weiter
  • category (wie durch den zweiten Parameter definiert) und value zuletzt .

Zusätzliche Spalten werden von der ersten an gefüllt Zeile aus jedem row_name Partition. Werte aus anderen Zeilen werden ignoriert, es gibt nur eine Spalte pro row_name füllen. Normalerweise wären diese für jede Zeile eines row_name gleich , aber das liegt an Ihnen.

Für die unterschiedliche Einrichtung in Ihrer Antwort:

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  -- ??!!

Kein Wunder, dass die Abfragen in Ihrem Test schrecklich abschneiden. Ihr Testaufbau hat 14 Millionen Zeilen und Sie verarbeiten alle von ihnen, bevor Sie das meiste davon mit LIMIT 1000 wegwerfen . Für eine reduzierte Ergebnismenge fügen Sie WHERE-Bedingungen oder ein LIMIT zur Quellabfrage hinzu!

Außerdem ist das Array, mit dem Sie arbeiten, unnötig teuer. Ich generiere stattdessen einen Ersatzzeilennamen mit dense_rank().

db<>fiddle hier - mit einem einfacheren Testaufbau und weniger Zeilen.