2010-03-19 35 views
6

Estoy tratando de crear una vista de tabla dinámica en postgresql y estoy a punto de hacerlo. Ésta es la consulta básica:manera correcta de crear una tabla dinámica en postgresql usando CASE CUANDO

select 
acc2tax_node.acc, tax_node.name, tax_node.rank 
from 
tax_node, acc2tax_node 
where 
tax_node.taxid=acc2tax_node.taxid and acc2tax_node.acc='AJ012531'; 

Y los datos:

acc |   name   |  rank  
----------+-------------------------+-------------- 
AJ012531 | Paromalostomum fusculum | species 
AJ012531 | Paromalostomum   | genus 
AJ012531 | Macrostomidae   | family 
AJ012531 | Macrostomida   | order 
AJ012531 | Macrostomorpha   | no rank 
AJ012531 | Turbellaria    | class 
AJ012531 | Platyhelminthes   | phylum 
AJ012531 | Acoelomata    | no rank 
AJ012531 | Bilateria    | no rank 
AJ012531 | Eumetazoa    | no rank 
AJ012531 | Metazoa     | kingdom 
AJ012531 | Fungi/Metazoa group  | no rank 
AJ012531 | Eukaryota    | superkingdom 
AJ012531 | cellular organisms  | no rank 

Lo que estoy tratando de conseguir es la siguiente:

acc  | species     | phylum 
AJ012531 | Paromalostomum fusculum | Platyhelminthes 

que estoy tratando de hacer esto con CASO CUANDO , así que tengo hasta lo siguiente:

select 
acc2tax_node.acc, 
CASE tax_node.rank WHEN 'species' THEN tax_node.name ELSE NULL END as species, 
CASE tax_node.rank WHEN 'phylum' THEN tax_node.name ELSE NULL END as phylum 
from 
tax_node, acc2tax_node 
where 
tax_node.taxid=acc2tax_node.taxid and acc2tax_node.acc='AJ012531'; 

Lo que me da la salida:

acc |   species   |  phylum  
----------+-------------------------+----------------- 
AJ012531 | Paromalostomum fusculum | 
AJ012531 |       | 
AJ012531 |       | 
AJ012531 |       | 
AJ012531 |       | 
AJ012531 |       | 
AJ012531 |       | Platyhelminthes 
AJ012531 |       | 
AJ012531 |       | 
AJ012531 |       | 
AJ012531 |       | 
AJ012531 |       | 
AJ012531 |       | 
AJ012531 |       | 

Ahora sé que tengo al grupo por el CAC en algún momento, así que trato

select 
acc2tax_node.acc, 
CASE tax_node.rank WHEN 'species' THEN tax_node.name ELSE NULL END as sp, 
CASE tax_node.rank WHEN 'phylum' THEN tax_node.name ELSE NULL END as ph 
from 
tax_node, acc2tax_node 
where 
tax_node.taxid=acc2tax_node.taxid and acc2tax_node.acc='AJ012531' 
group by acc2tax_node.acc; 

pero tengo la temida

ERROR: column "tax_node.rank" must appear in the GROUP BY clause or be used in an aggregate function 

Todos los ejemplos anteriores que he podido encontrar usan algo como SUM() alrededor de las sentencias CASE, así que supongo que esa es la función agregada. He intentado usar primero():

select 
acc2tax_node.acc, 
FIRST(CASE tax_node.rank WHEN 'species' THEN tax_node.name ELSE NULL END) as sp, 
FIRST(CASE tax_node.rank WHEN 'phylum' THEN tax_node.name ELSE NULL END) as ph 
from tax_node, acc2tax_node where tax_node.taxid=acc2tax_node.taxid and acc2tax_node.acc='AJ012531' group by acc2tax_node.acc; 

pero obtener el error:

ERROR: function first(character varying) does not exist 

¿Alguien puede ofrecer alguna pista?

+0

Podría por favor, puesto los resultados de esta consulta: ' SELECCIONAR * DESDE acc2tax_node DONDE acc = 'AJ012531''? – Quassnoi

Respuesta

5

Use MAX() o MIN(), no FIRST(). En este escenario, tendrá todos los NULL en la columna por cada valor de grupo excepto, como máximo, uno con un valor no nulo. Por definición, este es tanto el MIN como el MAX de ese conjunto de valores (todos los nulos están excluidos).

+0

Eso funciona perfectamente, gracias. Por alguna razón, asumí que MAX() no funcionaría porque estaba usando valores de cadena. – mojones

0
SELECT atn.acc, ts.name AS species, tp.name AS phylum 
FROM acc2tax_node atn 
LEFT JOIN 
     tax_node ts 
ON  ts.taxid = atn.taxid 
     AND ts.rank = 'species' 
LEFT JOIN 
     tax_node tp 
ON  tp.taxid = atn.taxid 
     AND tp.rank = 'phylum' 
WHERE atn.acc = 'AJ012531 ' 
+0

Disculpe mis terribles intentos de formatear :-) – mojones

0

Más información conforme a lo solicitado (en una respuesta más que un comentario para el formato agradable):

SELECT * FROM acc2tax_node WHERE acc = 'AJ012531'; 

    acc | taxid 
----------+-------- 
AJ012531 | 66400 
AJ012531 | 66399 
AJ012531 | 39216 
AJ012531 | 39215 
AJ012531 | 166235 
AJ012531 | 166384 
AJ012531 | 6157 
AJ012531 | 33214 
AJ012531 | 33213 
AJ012531 | 6072 
AJ012531 | 33208 
AJ012531 | 33154 
AJ012531 | 2759 
AJ012531 | 131567 
2

PostgreSQL tiene un par de funciones para las consultas de pivote, consulte este artículo en Postgresonline. Puede encontrar estas funciones en el contrib.

+0

Sí, sospecho que la forma correcta de hacerlo es con scrosstab. Todavía me gustaría descubrir qué estoy haciendo mal aquí para mi propia educación. – mojones

0

Ejecutar:

SELECT report.* FROM crosstab(
select 
acc2tax_node.acc, tax_node.name, tax_node.rank 
from 
tax_node, acc2tax_node 
where 
tax_node.taxid=acc2tax_node.taxid and acc2tax_node.acc='AJ012531'; 
) AS report(species text, enus text, family text, ...) 
0

Como Matthew Wood señaló, utilizar MIN() o MAX(), no en primer lugar():

SELECT 
    an.acc, 
    MAX(
     CASE tn.rank 
      WHEN 'species' THEN tn.name 
      ELSE NULL 
     END 
    ) AS species, 
    MAX(
     CASE tn.rank 
      WHEN 'phylum' THEN tn.name 
      ELSE NULL 
     END 
    ) AS phylum 
FROM tax_node tn, 
    acc2tax_node an 
WHERE tn.taxid = an.taxid 
    and an.acc = 'AJ012531' 
GROUP by an.acc; 
Cuestiones relacionadas