2010-12-01 21 views
6

Tengo una tabla (que es el resultado de una consulta) en postgres que tiene un conjunto de filas (el resultado de una complicada suma de datos) que se parece a lo siguiente: (Los nombres de columna son los nombres de cada día, y el valor de cada columna es un doble precisión.)¿pivote de Postgresql? Tabla cruzada?

Sun Lu         mar         Mier Jue Vier    
1,24     1,11     4,51     3,21       2,21         1,01

Es necesario disponer de los datos seleccionados de una fila por lo que los resultados se ven como el siguiente:

Día       Monto
Sun     1,24
Lu     1.11
mar   4.51
W ed     3,21
jue vie 2,21
          1,01

estoy teniendo dificultad acaba de empezar, ya que realmente necesito cambiar los nombres de las columnas con los valores y gire el resultado. Traté de experimentar con tablas cruzadas pero no estoy del todo seguro de que esto sea lo que necesito. Cualquier consejo o sugerencia que pueda hacerme avanzar en la dirección correcta sería muy apreciado.

+0

cuestión relacionada es http://stackoverflow.com/questions/1128737/unpivot-and-postgresql – Unreason

+0

Con * "experimentar con referencias cruzadas" * ¿se está refiriendo al módulo contrib de la tabla de referencias cruzadas? –

+1

sí Estaba mirando la función tablefunc.crosstab - http://www.postgresql.org/docs/current/static/tablefunc.html –

Respuesta

0

No sé de aplicación directa, pero tal vez algo como http://www.mail-archive.com/[email protected]/msg00109.html podría empezar

Por supuesto, si usted no necesita una solución flexible que puede hacer

SELECT 'Sun' AS Day, Sun AS Value FROM TABLE WHERE ... 
UNION ALL 
SELECT 'Mon' AS Day, Mon AS Value FROM TABLE WHERE ... 
UNION ALL 
SELECT 'Tue' AS Day, Tue AS Value FROM TABLE WHERE ... 
UNION ALL 
SELECT 'Wed' AS Day, Wed AS Value FROM TABLE WHERE ... 
UNION ALL 
SELECT 'Thu' AS Day, Thu AS Value FROM TABLE WHERE ... 
UNION ALL 
SELECT 'Fri' AS Day, Fri AS Value FROM TABLE WHERE ... 

(sábado?)

1

objetos de prueba:

create table t (sun numeric, 
       mon numeric, 
       tue numeric, 
       wed numeric, 
       thu numeric, 
       fri numeric); 

insert into t(sun, mon, tue, wed, thu, fri) 
values(1.24, 1.11, 4.51, 3.21, 2.21, 1.01); 

alternat ive a @ respuesta de Unreason sin union:

select day[i], amount[i] 
from (select generate_series(1,6) as i, 
       array['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri'] as day, 
       array[sun, mon, tue, wed, thu, fri] as amount 
     from t) z; 

si necesita ser más genérico que podría hacer algo como esto:

create or replace function unpivot(t) returns setof record 
          language plpgsql immutable strict as $$ 
declare 
    q record; 
    r record; 
begin 
    for q in (select attname, attnum 
      from pg_attribute 
      where attnum>0 and attrelid = (select oid 
              from pg_class 
              where relname = 't')) loop 
    for r in execute 'select '''||q.attname||'''::text, '|| 
          '('||$1::text||'::t).'||q.attname||'::numeric' loop 
     return next r; 
    end loop; 
    end loop; 
    return; 
end;$$; 

select * 
from unpivot((select row(t.*)::t from t)) 
     as foo(day text, amount numeric); 

puede ser un poco más ordenado en 8,4 con una cláusula using en la execute pero no se puede probar que estoy en primera respuesta 8.3

3

Modificación @Jack de Douglas:

SELECT unnest(array['sun', 'mon', 'tue', 'wed', 'thu', 'fri']) AS day, 
     unnest(array[sun, mon, tue, wed, thu, fri]) AS amount 
FROM t; 

Un poco menos costoso según el 9.0 consulta planificador:

Seq Scan on t (cost=0.00..11.62 rows=360 width=192)

frente

Subquery Scan on z (cost=0.00..12.16 rows=360 width=68) -> Seq Scan on t (cost=0.00..11.26 rows=360 width=192)